https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 #   $ ./a.elf < prog.mu > prog.elf
    7 
    8 # == Goals
    9 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
   10 # a bad pointer. (Requires strong type safety.)
   11 # 2. Do as little as possible to achieve goal 1. The translator should be
   12 # implementable in machine code.
   13 #   - minimize impedance mismatch between source language and SubX target
   14 #     (e.g. programmer manages registers manually)
   15 #   - checks over syntax
   16 #     (e.g. programmer's register allocation is checked)
   17 #   - runtime checks to avoid complex static analysis
   18 #     (e.g. array indexing always checks bounds)
   19 
   20 # == Language description
   21 # A program is a sequence of function and type definitions.
   22 #
   23 # Function example:
   24 #   fn foo n: int -> result/eax: int {
   25 #     ...
   26 #   }
   27 #
   28 # Functions consist of a name, optional inputs, optional outputs and a block.
   29 #
   30 # Function inputs and outputs are variables. All variables have a type and
   31 # storage specifier. They can be placed either in memory (on the stack) or in
   32 # one of 6 named registers.
   33 #   eax ecx edx ebx esi edi
   34 # Variables in registers must be primitive 32-bit types.
   35 # Variables not explicitly placed in a register are on the stack.
   36 #
   37 # Function inputs are always passed in memory (on the stack), while outputs
   38 # are always returned in registers.
   39 #
   40 # Blocks mostly consist of statements.
   41 #
   42 # Statements mostly consist of a name, optional inputs and optional outputs.
   43 #
   44 # Statement inputs are variables or literals. Variables need to specify type
   45 # (and storage) the first time they're mentioned but not later.
   46 #
   47 # Statement outputs, like function outputs, must be variables in registers.
   48 #
   49 # Statement names must be either primitives or user-defined functions.
   50 #
   51 # Primitives can write to any register.
   52 # User-defined functions only write to hard-coded registers. Outputs of each
   53 # call must have the same registers as in the function definition.
   54 #
   55 # There are some other statement types:
   56 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   57 #     prefixed with a label name and ':'
   58 #       - {
   59 #           ...
   60 #         }
   61 #       - foo: {
   62 #           ...
   63 #         }
   64 #
   65 #   - variable definitions on the stack. E.g.:
   66 #       - var foo: int
   67 #       - var bar: (array int 3)
   68 #     There's no initializer; variables are automatically initialized.
   69 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   70 #
   71 #   - variables definitions in a register. E.g.:
   72 #       - var foo/eax: int <- add bar 1
   73 #     The initializer is mandatory and must be a valid instruction that writes
   74 #     a single output to the right register. In practice registers will
   75 #     usually be either initialized by primitives or copied from eax.
   76 #       - var eax: int <- foo bar quux
   77 #         var floo/ecx: int <- copy eax
   78 #
   79 # Still todo:
   80 #   global variables
   81 #   union types
   82 #
   83 # Formal types:
   84 #   A program is a linked list of functions
   85 #   A function contains:
   86 #     name: (handle array byte)
   87 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   88 #       data: (handle var)
   89 #       next: (handle list)
   90 #     outputs: linked list of vars
   91 #       data: (handle var)
   92 #       next: (handle list)
   93 #     body: (handle block)
   94 #   A var-type contains:
   95 #     name: (handle array byte)
   96 #     type: (handle type-tree)
   97 #
   98 #   A statement can be:
   99 #     tag 0: a block
  100 #     tag 1: a simple statement (stmt1)
  101 #     tag 2: a variable defined on the stack
  102 #     tag 3: a variable defined in a register
  103 #
  104 #   A block contains:
  105 #     tag: 0
  106 #     statements: (handle list stmt)
  107 #     name: (handle array byte) -- starting with '$'
  108 #
  109 #   A regular statement contains:
  110 #     tag: 1
  111 #     operation: (handle array byte)
  112 #     inouts: (handle list operand)
  113 #     outputs: (handle list var)
  114 #
  115 #   A variable defined on the stack contains:
  116 #     tag: 2
  117 #     name: (handle array byte)
  118 #     type: (handle type-tree)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle type-tree)
  124 #     reg: (handle array byte)
  125 
  126 # == Translation: managing the stack
  127 # Now that we know what the language looks like in the large, let's think
  128 # about how translation happens from the bottom up. One crucial piece of the
  129 # puzzle is how Mu will clean up variables defined on the stack for you.
  130 #
  131 # Assume that we maintain a 'functions' list while parsing source code. And a
  132 # 'primitives' list is a global constant. Both these contain enough information
  133 # to perform type-checking on function calls or primitive statements, respectively.
  134 #
  135 # Defining variables pushes them on a stack with the current block depth and
  136 # enough information about their location (stack offset or register).
  137 # Starting a block increments the current block id.
  138 # Each statement now has enough information to emit code for it.
  139 # Ending a block is where the magic happens:
  140 #   pop all variables at the current block depth
  141 #   emit code to restore all register variables introduced at the current depth
  142 #   emit code to clean up all stack variables at the current depth (just increment esp)
  143 #   decrement the current block depth
  144 #
  145 # Formal types:
  146 #   live-vars: stack of vars
  147 #   var:
  148 #     name: (handle array byte)
  149 #     type: (handle type-tree)
  150 #     block: int
  151 #     stack-offset: int  (added to ebp)
  152 #     register: (handle array byte)
  153 #       either usual register names
  154 #       or '*' to indicate any register
  155 #   At most one of stack-offset or register-index must be non-zero.
  156 #   A register of '*' designates a variable _template_. Only legal in formal
  157 #   parameters for primitives.
  158 
  159 # == Translating a single function call
  160 # This one's easy. Assuming we've already checked things, we just drop the
  161 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  162 #
  163 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  164 # =>
  165 # (name inout1 inout2 inout3)
  166 #
  167 # Formal types:
  168 #   functions: linked list of info
  169 #     name: (handle array byte)
  170 #     inouts: linked list of vars
  171 #     outputs: linked list of vars
  172 #     body: block (linked list of statements)
  173 
  174 # == Translating a single primitive instruction
  175 # A second crucial piece of the puzzle is how Mu converts fairly regular
  176 # primitives with their uniform syntax to SubX instructions with their gnarly
  177 # x86 details.
  178 #
  179 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  180 # them.
  181 # SubX instructions have rm32 and r32 operands.
  182 # The translation between them covers almost all the possibilities.
  183 #   Instructions with 1 inout may turn into ones with 1 rm32
  184 #     (e.g. incrementing a var on the stack)
  185 #   Instructions with 1 output may turn into ones with 1 rm32
  186 #     (e.g. incrementing a var in a register)
  187 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  188 #     (e.g. adding a var to a reg)
  189 #   2 inouts may turn into 1 rm32 and 1 r32
  190 #     (e.g. adding a reg to a var)
  191 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  192 #     (e.g. adding a constant to a var)
  193 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  194 #     (e.g. adding a constant to a reg)
  195 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  196 #     (special-case: divide edx:eax by a var or reg)
  197 # Observations:
  198 #   We always emit rm32. It may be the first inout or the first output.
  199 #   We may emit r32 or imm32 or neither.
  200 #   When we emit r32 it may come from first inout or second inout or first output.
  201 #
  202 # Accordingly, the formal data structure for a primitive looks like this:
  203 #   primitives: linked list of info
  204 #     name: (handle array byte)
  205 #     mu-inouts: linked list of vars to check
  206 #     mu-outputs: linked list of vars to check; at most a singleton
  207 #     subx-name: (handle array byte)
  208 #     subx-rm32: enum arg-location
  209 #     subx-r32: enum arg-location
  210 #     subx-imm32: enum arg-location
  211 #     subx-imm8: enum arg-location
  212 #     subx-disp32: enum arg-location
  213 #     output-is-write-only: boolean
  214 #   arg-location: enum
  215 #     0 means none
  216 #     1 means first inout
  217 #     2 means second inout
  218 #     3 means first output
  219 
  220 # == Translating a block
  221 # Emit block name if necessary
  222 # Emit '{'
  223 # When you encounter a statement, emit it as above
  224 # When you encounter a variable declaration
  225 #   emit any code needed for it (bzeros)
  226 #   push it on the var stack
  227 #   update register dict if necessary
  228 # When you encounter '}'
  229 #   While popping variables off the var stack until block id changes
  230 #     Emit code needed to clean up the stack
  231 #       either increment esp
  232 #       or pop into appropriate register
  233 
  234 # The rest is straightforward.
  235 
  236 == data
  237 
  238 Program:
  239 _Program-functions:  # (handle function)
  240   0/imm32
  241 _Program-functions->payload:
  242   0/imm32
  243 _Program-types:  # (handle typeinfo)
  244   0/imm32
  245 _Program-types->payload:
  246   0/imm32
  247 _Program-signatures:  # (handle function)
  248   0/imm32
  249 _Program-signatures->payload:
  250   0/imm32
  251 
  252 # Some constants for simulating the data structures described above.
  253 # Many constants here come with a type in a comment.
  254 #
  255 # Sometimes the type is of the value at that offset for the given type. For
  256 # example, if you start at a function record and move forward Function-inouts
  257 # bytes, you'll find a (handle list var).
  258 #
  259 # At other times, the type is of the constant itself. For example, the type of
  260 # the constant Function-size is (addr int). To get the size of a function,
  261 # look in *Function-size.
  262 
  263 Function-name:  # (handle array byte)
  264   0/imm32
  265 Function-inouts:  # (handle list var)
  266   8/imm32
  267 Function-outputs:  # (handle list var)
  268   0x10/imm32
  269 Function-body:  # (handle block)
  270   0x18/imm32
  271 Function-next:  # (handle function)
  272   0x20/imm32
  273 Function-size:  # (addr int)
  274   0x28/imm32/40
  275 
  276 Primitive-name:  # (handle array byte)
  277   0/imm32
  278 Primitive-inouts:  # (handle list var)
  279   8/imm32
  280 Primitive-outputs:  # (handle list var)
  281   0x10/imm32
  282 Primitive-subx-name:  # (handle array byte)
  283   0x18/imm32
  284 Primitive-subx-rm32:  # enum arg-location
  285   0x20/imm32
  286 Primitive-subx-r32:  # enum arg-location
  287   0x24/imm32
  288 Primitive-subx-imm32:  # enum arg-location
  289   0x28/imm32
  290 Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
  291   0x2c/imm32
  292 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  293   0x30/imm32
  294 Primitive-output-is-write-only:  # boolean
  295   0x34/imm32
  296 Primitive-next:  # (handle function)
  297   0x38/imm32
  298 Primitive-size:  # (addr int)
  299   0x40/imm32/60
  300 
  301 Stmt-tag:  # int
  302   0/imm32
  303 
  304 Block-stmts:  # (handle list stmt)
  305   4/imm32
  306 Block-var:  # (handle var)
  307   0xc/imm32
  308 
  309 Stmt1-operation:  # (handle array byte)
  310   4/imm32
  311 Stmt1-inouts:  # (handle stmt-var)
  312   0xc/imm32
  313 Stmt1-outputs:  # (handle stmt-var)
  314   0x14/imm32
  315 
  316 Vardef-var:  # (handle var)
  317   4/imm32
  318 
  319 Regvardef-operation:  # (handle array byte)
  320   4/imm32
  321 Regvardef-inouts:  # (handle stmt-var)
  322   0xc/imm32
  323 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  324   0x14/imm32
  325 
  326 Stmt-size:  # (addr int)
  327   0x1c/imm32
  328 
  329 Var-name:  # (handle array byte)
  330   0/imm32
  331 Var-type:  # (handle type-tree)
  332   8/imm32
  333 Var-block-depth:  # int -- not available until code-generation time
  334   0x10/imm32
  335 Var-offset:  # int -- not available until code-generation time
  336   0x14/imm32
  337 Var-register:  # (handle array byte) -- name of a register
  338   0x18/imm32
  339 Var-size:  # (addr int)
  340   0x20/imm32
  341 
  342 List-value:  # (handle _)
  343   0/imm32
  344 List-next:  # (handle list _)
  345   8/imm32
  346 List-size:  # (addr int)
  347   0x10/imm32
  348 
  349 # A stmt-var is like a list of vars with call-site specific metadata
  350 Stmt-var-value:  # (handle var)
  351   0/imm32
  352 Stmt-var-next:  # (handle stmt-var)
  353   8/imm32
  354 Stmt-var-is-deref:  # boolean
  355   0x10/imm32
  356 Stmt-var-size:  # (addr int)
  357   0x14/imm32
  358 
  359 # A live-var is a var augmented with information needed for tracking live
  360 # variables.
  361 Live-var-value:  # (handle var)
  362   0/imm32
  363 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  364   8/imm32
  365 Live-var-size:  # (addr int)
  366   0xc/imm32
  367 
  368 # Types are expressed as trees (s-expressions) of type-ids (ints).
  369 
  370 Type-tree-is-atom:  # boolean
  371   0/imm32
  372 # if is-atom?
  373 Type-tree-value:  # type-id
  374   4/imm32
  375 Type-tree-value-size:  # int (for static data structure sizes)
  376   8/imm32
  377 Type-tree-parameter-name:  # (handle array byte) for type parameters
  378   8/imm32
  379 # unless is-atom?
  380 Type-tree-left:  # (addr type-tree)
  381   4/imm32
  382 Type-tree-right:  # (addr type-tree)
  383   0xc/imm32
  384 #
  385 Type-tree-size:  # (addr int)
  386   0x14/imm32
  387 
  388 # Types
  389 
  390 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  391 Type-id:  # (stream (addr array byte))
  392   0/imm32/write  # initialized later from Primitive-type-ids
  393   0/imm32/read
  394   0x100/imm32/size
  395   # data
  396   0/imm32  # 0 reserved for literals; value is just the name
  397            # Not to be used directly, so we don't include a name here.
  398   "int"/imm32  # 1
  399   "addr"/imm32  # 2
  400   "array"/imm32  # 3
  401   "handle"/imm32  # 4
  402   "boolean"/imm32  # 5
  403   0/imm32  # 6 reserved for constants; they're like literals, but value is an int in Var-offset
  404            # Not to be used directly, so we don't include a name here.
  405   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  406   # 0x20
  407   "byte"/imm32  # 8
  408   0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
  409            # Not to be used directly, so we don't include a name here.
  410   0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
  411            # Not to be used directly, so we don't include a name here.
  412   # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives
  413   "stream"/imm32  # 11
  414   "slice"/imm32  # 12
  415   "code-point"/imm32  # 13; smallest scannable unit from a text stream
  416   "grapheme"/imm32  # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1
  417                     # only 4-byte graphemes in utf-8 are currently supported;
  418                     # unclear how we should deal with larger clusters.
  419   # Keep Primitive-type-ids in sync if you add types here.
  420                                                           0/imm32
  421   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  422   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  423   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  424   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  425   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  426   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  427 
  428 Primitive-type-ids:  # (addr int)
  429   0x34
  430 
  431 # == Type definitions
  432 # Program->types contains some typeinfo for each type definition.
  433 # Types contain vars with types, but can't specify registers.
  434 Typeinfo-id:  # type-id
  435   0/imm32
  436 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  437   4/imm32
  438 # Total size must be >= 0
  439 # During parsing it may take on two additional values:
  440 #   -2: not yet initialized
  441 #   -1: in process of being computed
  442 # See populate-mu-type-sizes for details.
  443 Typeinfo-total-size-in-bytes:  # int
  444   0xc/imm32
  445 Typeinfo-next:  # (handle typeinfo)
  446   0x10/imm32
  447 Typeinfo-size:  # (addr int)
  448   0x18/imm32
  449 
  450 # Each entry in the typeinfo->fields table has a pointer to a string and a
  451 # pointer to a typeinfo-entry.
  452 Typeinfo-fields-row-size:  # (addr int)
  453   0x10/imm32
  454 
  455 # typeinfo-entry objects have information about a field in a single record type
  456 #
  457 # each field of a type is represented using two var's:
  458 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  459 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  460 # computing the output happens after parsing; in the meantime we preserve the
  461 # order of fields in the 'index' field.
  462 Typeinfo-entry-input-var:  # (handle var)
  463   0/imm32
  464 Typeinfo-entry-index:  # int
  465   8/imm32
  466 Typeinfo-entry-output-var:  # (handle var)
  467   0xc/imm32
  468 Typeinfo-entry-size:  # (addr int)
  469   0x14/imm32
  470 
  471 == code
  472 
  473 Entry:
  474     # . prologue
  475     89/<- %ebp 4/r32/esp
  476     (new-segment *Heap-size Heap)
  477     # if (argv[1] == "test') run-tests()
  478     {
  479       # if (argc <= 1) break
  480       81 7/subop/compare *ebp 1/imm32
  481       7e/jump-if-<= break/disp8
  482       # if (argv[1] != "test") break
  483       (kernel-string-equal? *(ebp+8) "test")  # => eax
  484       3d/compare-eax-and 0/imm32/false
  485       74/jump-if-= break/disp8
  486       #
  487       (run-tests)
  488       # syscall(exit, *Num-test-failures)
  489       8b/-> *Num-test-failures 3/r32/ebx
  490       eb/jump $mu-main:end/disp8
  491     }
  492     # otherwise convert Stdin
  493     (convert-mu Stdin Stdout Stderr 0)
  494     (flush Stdout)
  495     # syscall(exit, 0)
  496     bb/copy-to-ebx 0/imm32
  497 $mu-main:end:
  498     e8/call syscall_exit/disp32
  499 
  500 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  501     # . prologue
  502     55/push-ebp
  503     89/<- %ebp 4/r32/esp
  504     # . save registers
  505     50/push-eax
  506     # initialize global data structures
  507     c7 0/subop/copy *Next-block-index 1/imm32
  508     8b/-> *Primitive-type-ids 0/r32/eax
  509     89/<- *Type-id 0/r32/eax  # stream-write
  510     c7 0/subop/copy *_Program-functions 0/imm32
  511     c7 0/subop/copy *_Program-functions->payload 0/imm32
  512     c7 0/subop/copy *_Program-types 0/imm32
  513     c7 0/subop/copy *_Program-types->payload 0/imm32
  514     c7 0/subop/copy *_Program-signatures 0/imm32
  515     c7 0/subop/copy *_Program-signatures->payload 0/imm32
  516     #
  517     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  518     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  519 #?     (dump-typeinfos "=== typeinfos\n")
  520     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  521     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  522 $convert-mu:end:
  523     # . restore registers
  524     58/pop-to-eax
  525     # . epilogue
  526     89/<- %esp 5/r32/ebp
  527     5d/pop-to-ebp
  528     c3/return
  529 
  530 test-convert-empty-input:
  531     # empty input => empty output
  532     # . prologue
  533     55/push-ebp
  534     89/<- %ebp 4/r32/esp
  535     # setup
  536     (clear-stream _test-input-stream)
  537     (clear-stream $_test-input-buffered-file->buffer)
  538     (clear-stream _test-output-stream)
  539     (clear-stream $_test-output-buffered-file->buffer)
  540     #
  541     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  542     (flush _test-output-buffered-file)
  543     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  544     # . epilogue
  545     89/<- %esp 5/r32/ebp
  546     5d/pop-to-ebp
  547     c3/return
  548 
  549 test-convert-function-skeleton:
  550     # . prologue
  551     55/push-ebp
  552     89/<- %ebp 4/r32/esp
  553     # setup
  554     (clear-stream _test-input-stream)
  555     (clear-stream $_test-input-buffered-file->buffer)
  556     (clear-stream _test-output-stream)
  557     (clear-stream $_test-output-buffered-file->buffer)
  558     #
  559     (write _test-input-stream "fn foo {\n")
  560     (write _test-input-stream "}\n")
  561     # convert
  562     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  563     (flush _test-output-buffered-file)
  564 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  570     # check output
  571     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  572     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  573     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  574     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  575     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  576     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  577     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  578     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  579     # . epilogue
  580     89/<- %esp 5/r32/ebp
  581     5d/pop-to-ebp
  582     c3/return
  583 
  584 test-convert-multiple-function-skeletons:
  585     # . prologue
  586     55/push-ebp
  587     89/<- %ebp 4/r32/esp
  588     # setup
  589     (clear-stream _test-input-stream)
  590     (clear-stream $_test-input-buffered-file->buffer)
  591     (clear-stream _test-output-stream)
  592     (clear-stream $_test-output-buffered-file->buffer)
  593     #
  594     (write _test-input-stream "fn foo {\n")
  595     (write _test-input-stream "}\n")
  596     (write _test-input-stream "fn bar {\n")
  597     (write _test-input-stream "}\n")
  598     # convert
  599     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  600     (flush _test-output-buffered-file)
  601 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  607     # check first function
  608     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  609     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  610     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  611     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  612     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  613     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  614     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  615     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  616     # check second function
  617     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  618     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  619     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  620     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  622     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  623     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  625     # . epilogue
  626     89/<- %esp 5/r32/ebp
  627     5d/pop-to-ebp
  628     c3/return
  629 
  630 test-convert-function-with-arg:
  631     # . prologue
  632     55/push-ebp
  633     89/<- %ebp 4/r32/esp
  634     # setup
  635     (clear-stream _test-input-stream)
  636     (clear-stream $_test-input-buffered-file->buffer)
  637     (clear-stream _test-output-stream)
  638     (clear-stream $_test-output-buffered-file->buffer)
  639     #
  640     (write _test-input-stream "fn foo n: int {\n")
  641     (write _test-input-stream "}\n")
  642     # convert
  643     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  644     (flush _test-output-buffered-file)
  645 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  651     # check output
  652     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  653     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  654     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  655     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  656     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  657     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  658     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  659     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  660     # . epilogue
  661     89/<- %esp 5/r32/ebp
  662     5d/pop-to-ebp
  663     c3/return
  664 
  665 test-convert-function-with-arg-and-body:
  666     # . prologue
  667     55/push-ebp
  668     89/<- %ebp 4/r32/esp
  669     # setup
  670     (clear-stream _test-input-stream)
  671     (clear-stream $_test-input-buffered-file->buffer)
  672     (clear-stream _test-output-stream)
  673     (clear-stream $_test-output-buffered-file->buffer)
  674     #
  675     (write _test-input-stream "fn foo n: int {\n")
  676     (write _test-input-stream "  increment n\n")
  677     (write _test-input-stream "}\n")
  678     # convert
  679     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  680     (flush _test-output-buffered-file)
  681 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  687     # check output
  688     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  689     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  690     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  691     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  692     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  693     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  694     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  695     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  696     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  697     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  698     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  699     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  700     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  701     # . epilogue
  702     89/<- %esp 5/r32/ebp
  703     5d/pop-to-ebp
  704     c3/return
  705 
  706 test-convert-function-distinguishes-args:
  707     # . prologue
  708     55/push-ebp
  709     89/<- %ebp 4/r32/esp
  710     # setup
  711     (clear-stream _test-input-stream)
  712     (clear-stream $_test-input-buffered-file->buffer)
  713     (clear-stream _test-output-stream)
  714     (clear-stream $_test-output-buffered-file->buffer)
  715     #
  716     (write _test-input-stream "fn foo a: int, b: int {\n")
  717     (write _test-input-stream "  increment b\n")
  718     (write _test-input-stream "}\n")
  719     # convert
  720     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  721     (flush _test-output-buffered-file)
  722 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  728     # check output
  729     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  730     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  731     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  732     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  733     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  735     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  736     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  737     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  738     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  739     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  740     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  741     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  742     # . epilogue
  743     89/<- %esp 5/r32/ebp
  744     5d/pop-to-ebp
  745     c3/return
  746 
  747 test-convert-function-returns-result:
  748     # . prologue
  749     55/push-ebp
  750     89/<- %ebp 4/r32/esp
  751     # setup
  752     (clear-stream _test-input-stream)
  753     (clear-stream $_test-input-buffered-file->buffer)
  754     (clear-stream _test-output-stream)
  755     (clear-stream $_test-output-buffered-file->buffer)
  756     #
  757     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  758     (write _test-input-stream "  result <- copy a\n")
  759     (write _test-input-stream "  result <- increment\n")
  760     (write _test-input-stream "}\n")
  761     # convert
  762     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  763     (flush _test-output-buffered-file)
  764 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  770     # check output
  771     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  772     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  773     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  774     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  775     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  777     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  778     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  779     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  780     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  781     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  782     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  783     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  784     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  785     # . epilogue
  786     89/<- %esp 5/r32/ebp
  787     5d/pop-to-ebp
  788     c3/return
  789 
  790 test-convert-function-with-literal-arg:
  791     # . prologue
  792     55/push-ebp
  793     89/<- %ebp 4/r32/esp
  794     # setup
  795     (clear-stream _test-input-stream)
  796     (clear-stream $_test-input-buffered-file->buffer)
  797     (clear-stream _test-output-stream)
  798     (clear-stream $_test-output-buffered-file->buffer)
  799     #
  800     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  801     (write _test-input-stream "  result <- copy a\n")
  802     (write _test-input-stream "  result <- add 1\n")
  803     (write _test-input-stream "}\n")
  804     # convert
  805     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  806     (flush _test-output-buffered-file)
  807 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  813     # check output
  814     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  815     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  816     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  817     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  818     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  820     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  821     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  822     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  824     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  825     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  826     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  827     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  828     # . epilogue
  829     89/<- %esp 5/r32/ebp
  830     5d/pop-to-ebp
  831     c3/return
  832 
  833 test-convert-function-with-literal-arg-2:
  834     # . prologue
  835     55/push-ebp
  836     89/<- %ebp 4/r32/esp
  837     # setup
  838     (clear-stream _test-input-stream)
  839     (clear-stream $_test-input-buffered-file->buffer)
  840     (clear-stream _test-output-stream)
  841     (clear-stream $_test-output-buffered-file->buffer)
  842     #
  843     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  844     (write _test-input-stream "  result <- copy a\n")
  845     (write _test-input-stream "  result <- add 1\n")
  846     (write _test-input-stream "}\n")
  847     # convert
  848     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  849     (flush _test-output-buffered-file)
  850 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  856     # check output
  857     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  858     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  859     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  860     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  861     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  862     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  863     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  864     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  865     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  866     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  867     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  868     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  869     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  870     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  871     # . epilogue
  872     89/<- %esp 5/r32/ebp
  873     5d/pop-to-ebp
  874     c3/return
  875 
  876 test-convert-function-call-with-literal-arg:
  877     # . prologue
  878     55/push-ebp
  879     89/<- %ebp 4/r32/esp
  880     # setup
  881     (clear-stream _test-input-stream)
  882     (clear-stream $_test-input-buffered-file->buffer)
  883     (clear-stream _test-output-stream)
  884     (clear-stream $_test-output-buffered-file->buffer)
  885     #
  886     (write _test-input-stream "fn main -> result/ebx: int {\n")
  887     (write _test-input-stream "  result <- do-add 3 4\n")
  888     (write _test-input-stream "}\n")
  889     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  890     (write _test-input-stream "  result <- copy a\n")
  891     (write _test-input-stream "  result <- add b\n")
  892     (write _test-input-stream "}\n")
  893     # convert
  894     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  895     (flush _test-output-buffered-file)
  896 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  902     # check output
  903     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  904     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  905     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  906     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  907     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  908     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  909     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  910     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  911     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  912     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  913     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  914     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  915     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  916     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  917     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  918     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  919     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  920     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  921     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  922     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  923     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  924     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  925     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  926     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  927     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  928     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  929     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  930     # . epilogue
  931     89/<- %esp 5/r32/ebp
  932     5d/pop-to-ebp
  933     c3/return
  934 
  935 test-convert-function-call-with-signature:
  936     # . prologue
  937     55/push-ebp
  938     89/<- %ebp 4/r32/esp
  939     # setup
  940     (clear-stream _test-input-stream)
  941     (clear-stream $_test-input-buffered-file->buffer)
  942     (clear-stream _test-output-stream)
  943     (clear-stream $_test-output-buffered-file->buffer)
  944     #
  945     (write _test-input-stream "fn main -> result/ebx: int {\n")
  946     (write _test-input-stream "  result <- do-add 3 4\n")
  947     (write _test-input-stream "}\n")
  948     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  949     # convert
  950     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  951     (flush _test-output-buffered-file)
  952 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
  958     # check output
  959     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  960     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  961     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  962     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  963     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  964     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  965     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  966     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  967     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  968     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  969     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  970     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  971     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  972     # . epilogue
  973     89/<- %esp 5/r32/ebp
  974     5d/pop-to-ebp
  975     c3/return
  976 
  977 test-convert-function-with-local-var-in-mem:
  978     # . prologue
  979     55/push-ebp
  980     89/<- %ebp 4/r32/esp
  981     # setup
  982     (clear-stream _test-input-stream)
  983     (clear-stream $_test-input-buffered-file->buffer)
  984     (clear-stream _test-output-stream)
  985     (clear-stream $_test-output-buffered-file->buffer)
  986     #
  987     (write _test-input-stream "fn foo {\n")
  988     (write _test-input-stream "  var x: int\n")
  989     (write _test-input-stream "  increment x\n")
  990     (write _test-input-stream "}\n")
  991     # convert
  992     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  993     (flush _test-output-buffered-file)
  994 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1000     # check output
 1001     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
 1002     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
 1003     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
 1004     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
 1005     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
 1006     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
 1007     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
 1008     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
 1009     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem/8")
 1010     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
 1011     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
 1012     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
 1013     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
 1014     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
 1015     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
 1016     # . epilogue
 1017     89/<- %esp 5/r32/ebp
 1018     5d/pop-to-ebp
 1019     c3/return
 1020 
 1021 test-convert-invalid-literal:
 1022     # . prologue
 1023     55/push-ebp
 1024     89/<- %ebp 4/r32/esp
 1025     # setup
 1026     (clear-stream _test-input-stream)
 1027     (clear-stream $_test-input-buffered-file->buffer)
 1028     (clear-stream _test-output-stream)
 1029     (clear-stream $_test-output-buffered-file->buffer)
 1030     (clear-stream _test-error-stream)
 1031     (clear-stream $_test-error-buffered-file->buffer)
 1032     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1033     68/push 0/imm32
 1034     68/push 0/imm32
 1035     89/<- %edx 4/r32/esp
 1036     (tailor-exit-descriptor %edx 0x10)
 1037     #
 1038     (write _test-input-stream "fn foo {\n")
 1039     (write _test-input-stream "  increment 1n\n")
 1040     (write _test-input-stream "}\n")
 1041     # convert
 1042     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1043     # registers except esp clobbered at this point
 1044     # restore ed
 1045     89/<- %edx 4/r32/esp
 1046     (flush _test-output-buffered-file)
 1047     (flush _test-error-buffered-file)
 1048 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1054     # check output
 1055     (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
 1056     (check-next-stream-line-equal _test-error-stream  "fn foo: variable '1n' cannot begin with a digit (or do you have a typo in a number?)"  "F - test-convert-invalid-literal: error message")
 1057     # check that stop(1) was called
 1058     (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
 1059     # don't restore from ebp
 1060     81 0/subop/add %esp 8/imm32
 1061     # . epilogue
 1062     5d/pop-to-ebp
 1063     c3/return
 1064 
 1065 test-local-var-in-mem-has-no-initializer:
 1066     # . prologue
 1067     55/push-ebp
 1068     89/<- %ebp 4/r32/esp
 1069     # setup
 1070     (clear-stream _test-input-stream)
 1071     (clear-stream $_test-input-buffered-file->buffer)
 1072     (clear-stream _test-output-stream)
 1073     (clear-stream $_test-output-buffered-file->buffer)
 1074     (clear-stream _test-error-stream)
 1075     (clear-stream $_test-error-buffered-file->buffer)
 1076     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1077     68/push 0/imm32
 1078     68/push 0/imm32
 1079     89/<- %edx 4/r32/esp
 1080     (tailor-exit-descriptor %edx 0x10)
 1081     #
 1082     (write _test-input-stream "fn foo {\n")
 1083     (write _test-input-stream "  var x: int <- copy 0\n")
 1084     (write _test-input-stream "  increment x\n")
 1085     (write _test-input-stream "}\n")
 1086     # convert
 1087     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1088     # registers except esp clobbered at this point
 1089     # restore ed
 1090     89/<- %edx 4/r32/esp
 1091     (flush _test-output-buffered-file)
 1092     (flush _test-error-buffered-file)
 1093 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1099     # check output
 1100     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1101     (check-next-stream-line-equal _test-error-stream  "fn foo: var x: variables on the stack can't take an initializer"  "F - test-var-in-mem-has-no-initializer: error message")
 1102     # check that stop(1) was called
 1103     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1104     # don't restore from ebp
 1105     81 0/subop/add %esp 8/imm32
 1106     # . epilogue
 1107     5d/pop-to-ebp
 1108     c3/return
 1109 
 1110 test-convert-function-with-local-var-with-compound-type-in-mem:
 1111     # . prologue
 1112     55/push-ebp
 1113     89/<- %ebp 4/r32/esp
 1114     # setup
 1115     (clear-stream _test-input-stream)
 1116     (clear-stream $_test-input-buffered-file->buffer)
 1117     (clear-stream _test-output-stream)
 1118     (clear-stream $_test-output-buffered-file->buffer)
 1119     #
 1120     (write _test-input-stream "fn foo {\n")
 1121     (write _test-input-stream "  var x: (addr int)\n")
 1122     (write _test-input-stream "  copy-to x, 0\n")
 1123     (write _test-input-stream "}\n")
 1124     # convert
 1125     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1126     (flush _test-output-buffered-file)
 1127 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1133     # check output
 1134     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1135     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1136     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1137     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/3")
 1138     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1139     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1140     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-compound-type-in-mem/6")
 1141     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/7")
 1142     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/8")
 1143     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1144     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1145     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1146     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/12")
 1147     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-compound-type-in-mem/13")
 1148     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1149     # . epilogue
 1150     89/<- %esp 5/r32/ebp
 1151     5d/pop-to-ebp
 1152     c3/return
 1153 
 1154 test-convert-function-with-local-var-in-reg:
 1155     # . prologue
 1156     55/push-ebp
 1157     89/<- %ebp 4/r32/esp
 1158     # setup
 1159     (clear-stream _test-input-stream)
 1160     (clear-stream $_test-input-buffered-file->buffer)
 1161     (clear-stream _test-output-stream)
 1162     (clear-stream $_test-output-buffered-file->buffer)
 1163     #
 1164     (write _test-input-stream "fn foo {\n")
 1165     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1166     (write _test-input-stream "  x <- increment\n")
 1167     (write _test-input-stream "}\n")
 1168     # convert
 1169     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1170     (flush _test-output-buffered-file)
 1171 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1177     # check output
 1178     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1179     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1180     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1181     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1182     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1184     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1185     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1186     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1187     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1188     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1189     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1190     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1191     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1192     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1193     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1194     # . epilogue
 1195     89/<- %esp 5/r32/ebp
 1196     5d/pop-to-ebp
 1197     c3/return
 1198 
 1199 test-convert-function-with-allocate:
 1200     # . prologue
 1201     55/push-ebp
 1202     89/<- %ebp 4/r32/esp
 1203     # setup
 1204     (clear-stream _test-input-stream)
 1205     (clear-stream $_test-input-buffered-file->buffer)
 1206     (clear-stream _test-output-stream)
 1207     (clear-stream $_test-output-buffered-file->buffer)
 1208     #
 1209     (write _test-input-stream "fn foo {\n")
 1210     (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
 1211     (write _test-input-stream "  allocate x\n")
 1212     (write _test-input-stream "}\n")
 1213     # convert
 1214     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1215     (flush _test-output-buffered-file)
 1216 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1222     # check output
 1223     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
 1224     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
 1225     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
 1226     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
 1227     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
 1228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
 1229     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
 1230     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
 1231     (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
 1232     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
 1233     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
 1234     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
 1235     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
 1236     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
 1237     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
 1238     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
 1239     # . epilogue
 1240     89/<- %esp 5/r32/ebp
 1241     5d/pop-to-ebp
 1242     c3/return
 1243 
 1244 test-initializer-in-hex:
 1245     # . prologue
 1246     55/push-ebp
 1247     89/<- %ebp 4/r32/esp
 1248     # setup
 1249     (clear-stream _test-input-stream)
 1250     (clear-stream $_test-input-buffered-file->buffer)
 1251     (clear-stream _test-output-stream)
 1252     (clear-stream $_test-output-buffered-file->buffer)
 1253     (clear-stream _test-error-stream)
 1254     (clear-stream $_test-error-buffered-file->buffer)
 1255     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1256     68/push 0/imm32
 1257     68/push 0/imm32
 1258     89/<- %edx 4/r32/esp
 1259     (tailor-exit-descriptor %edx 0x10)
 1260     #
 1261     (write _test-input-stream "fn foo {\n")
 1262     (write _test-input-stream "  var x/ecx: int <- copy 10\n")
 1263     (write _test-input-stream "}\n")
 1264     # convert
 1265     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1266     # registers except esp clobbered at this point
 1267     # restore ed
 1268     89/<- %edx 4/r32/esp
 1269     (flush _test-output-buffered-file)
 1270     (flush _test-error-buffered-file)
 1271 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1277     # check output
 1278     (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
 1279     (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-initializer-in-hex: error message")
 1280     # check that stop(1) was called
 1281     (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
 1282     # don't restore from ebp
 1283     81 0/subop/add %esp 8/imm32
 1284     # . epilogue
 1285     5d/pop-to-ebp
 1286     c3/return
 1287 
 1288 test-convert-function-with-second-local-var-in-same-reg:
 1289     # . prologue
 1290     55/push-ebp
 1291     89/<- %ebp 4/r32/esp
 1292     # setup
 1293     (clear-stream _test-input-stream)
 1294     (clear-stream $_test-input-buffered-file->buffer)
 1295     (clear-stream _test-output-stream)
 1296     (clear-stream $_test-output-buffered-file->buffer)
 1297     #
 1298     (write _test-input-stream "fn foo {\n")
 1299     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1300     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1301     (write _test-input-stream "  y <- increment\n")
 1302     (write _test-input-stream "}\n")
 1303     # convert
 1304     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1305     (flush _test-output-buffered-file)
 1306 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1312     # check output
 1313     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1314     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1315     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1316     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-second-local-var-in-same-reg/3")
 1317     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1318     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1319     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-second-local-var-in-same-reg/6")
 1320     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/7")
 1321     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/8")
 1322     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1323     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10")
 1324     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1325     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1326     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1327     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-second-local-var-in-same-reg/14")
 1328     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1329     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1330     # . epilogue
 1331     89/<- %esp 5/r32/ebp
 1332     5d/pop-to-ebp
 1333     c3/return
 1334 
 1335 test-read-clobbered-reg-var:
 1336     # . prologue
 1337     55/push-ebp
 1338     89/<- %ebp 4/r32/esp
 1339     # setup
 1340     (clear-stream _test-input-stream)
 1341     (clear-stream $_test-input-buffered-file->buffer)
 1342     (clear-stream _test-output-stream)
 1343     (clear-stream $_test-output-buffered-file->buffer)
 1344     (clear-stream _test-error-stream)
 1345     (clear-stream $_test-error-buffered-file->buffer)
 1346     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1347     68/push 0/imm32
 1348     68/push 0/imm32
 1349     89/<- %edx 4/r32/esp
 1350     (tailor-exit-descriptor %edx 0x10)
 1351     #
 1352     (write _test-input-stream "fn foo {\n")
 1353     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1354     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1355     (write _test-input-stream "  x <- increment\n")
 1356     (write _test-input-stream "}\n")
 1357     # convert
 1358     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1359     # registers except esp clobbered at this point
 1360     # restore ed
 1361     89/<- %edx 4/r32/esp
 1362     (flush _test-output-buffered-file)
 1363     (flush _test-error-buffered-file)
 1364 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1370     # check output
 1371     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1372     (check-next-stream-line-equal _test-error-stream  "fn foo: register ecx reads var 'x' after writing var 'y'"  "F - test-read-clobbered-reg-var: error message")
 1373     # check that stop(1) was called
 1374     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1375     # don't restore from ebp
 1376     81 0/subop/add %esp 8/imm32
 1377     # . epilogue
 1378     5d/pop-to-ebp
 1379     c3/return
 1380 
 1381 test-convert-function-call:
 1382     # . prologue
 1383     55/push-ebp
 1384     89/<- %ebp 4/r32/esp
 1385     # setup
 1386     (clear-stream _test-input-stream)
 1387     (clear-stream $_test-input-buffered-file->buffer)
 1388     (clear-stream _test-output-stream)
 1389     (clear-stream $_test-output-buffered-file->buffer)
 1390     #
 1391     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1392     (write _test-input-stream "  result <- foo\n")
 1393     (write _test-input-stream "}\n")
 1394     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1395     (write _test-input-stream "  result <- copy 3\n")
 1396     (write _test-input-stream "}\n")
 1397     # convert
 1398     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1399     (flush _test-output-buffered-file)
 1400 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1406     # check output
 1407     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1408     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1409     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1410     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1411     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1412     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1413     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1414     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1415     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1416     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1417     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1418     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1419     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1420     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1421     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1422     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1423     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1424     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1425     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1426     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1427     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1428     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1429     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1430     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1431     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1432     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1433     # . epilogue
 1434     89/<- %esp 5/r32/ebp
 1435     5d/pop-to-ebp
 1436     c3/return
 1437 
 1438 test-convert-function-call-with-inout-with-compound-type:
 1439     # . prologue
 1440     55/push-ebp
 1441     89/<- %ebp 4/r32/esp
 1442     # setup
 1443     (clear-stream _test-input-stream)
 1444     (clear-stream $_test-input-buffered-file->buffer)
 1445     (clear-stream _test-output-stream)
 1446     (clear-stream $_test-output-buffered-file->buffer)
 1447     #
 1448     (write _test-input-stream "fn f {\n")
 1449     (write _test-input-stream "  var x: (addr int)\n")
 1450     (write _test-input-stream "  g x\n")
 1451     (write _test-input-stream "}\n")
 1452     (write _test-input-stream "fn g a: (addr int) {\n")
 1453     (write _test-input-stream "}\n")
 1454     # convert
 1455     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1456     (flush _test-output-buffered-file)
 1457 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1463     # check output
 1464     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
 1465     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
 1466     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
 1467     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
 1468     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
 1469     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
 1470     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
 1471     (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
 1472     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-call-with-inout-with-compound-type/8")
 1473     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
 1474     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
 1475     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
 1476     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
 1477     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
 1478     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
 1479     (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
 1480     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
 1481     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
 1482     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
 1483     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
 1484     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
 1485     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
 1486     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
 1487     # . epilogue
 1488     89/<- %esp 5/r32/ebp
 1489     5d/pop-to-ebp
 1490     c3/return
 1491 
 1492 test-convert-function-call-with-inout-with-type-parameter:
 1493     # . prologue
 1494     55/push-ebp
 1495     89/<- %ebp 4/r32/esp
 1496     # setup
 1497     (clear-stream _test-input-stream)
 1498     (clear-stream $_test-input-buffered-file->buffer)
 1499     (clear-stream _test-output-stream)
 1500     (clear-stream $_test-output-buffered-file->buffer)
 1501     (clear-stream _test-error-stream)
 1502     (clear-stream $_test-error-buffered-file->buffer)
 1503     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1504     68/push 0/imm32
 1505     68/push 0/imm32
 1506     89/<- %edx 4/r32/esp
 1507     (tailor-exit-descriptor %edx 0x10)
 1508     #
 1509     (write _test-input-stream "fn f {\n")
 1510     (write _test-input-stream "  var x: (addr int)\n")
 1511     (write _test-input-stream "  g x\n")
 1512     (write _test-input-stream "}\n")
 1513     (write _test-input-stream "fn g a: (addr _) {\n")
 1514     (write _test-input-stream "}\n")
 1515     # convert
 1516     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1517     # registers except esp clobbered at this point
 1518     # restore ed
 1519     89/<- %edx 4/r32/esp
 1520     (flush _test-output-buffered-file)
 1521     (flush _test-error-buffered-file)
 1522 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1528     # no error; types matched
 1529     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
 1530     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 1531     # don't restore from ebp
 1532     81 0/subop/add %esp 8/imm32
 1533     # . epilogue
 1534     5d/pop-to-ebp
 1535     c3/return
 1536 
 1537 test-convert-function-call-with-incorrect-inout-type:
 1538     # . prologue
 1539     55/push-ebp
 1540     89/<- %ebp 4/r32/esp
 1541     # setup
 1542     (clear-stream _test-input-stream)
 1543     (clear-stream $_test-input-buffered-file->buffer)
 1544     (clear-stream _test-output-stream)
 1545     (clear-stream $_test-output-buffered-file->buffer)
 1546     (clear-stream _test-error-stream)
 1547     (clear-stream $_test-error-buffered-file->buffer)
 1548     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1549     68/push 0/imm32
 1550     68/push 0/imm32
 1551     89/<- %edx 4/r32/esp
 1552     (tailor-exit-descriptor %edx 0x10)
 1553     #
 1554     (write _test-input-stream "fn f {\n")
 1555     (write _test-input-stream "  var x: int\n")
 1556     (write _test-input-stream "  g x\n")
 1557     (write _test-input-stream "}\n")
 1558     (write _test-input-stream "fn g a: foo {\n")
 1559     (write _test-input-stream "}\n")
 1560     # convert
 1561     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1562     # registers except esp clobbered at this point
 1563     # restore ed
 1564     89/<- %edx 4/r32/esp
 1565     (flush _test-output-buffered-file)
 1566     (flush _test-error-buffered-file)
 1567 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1573     # check output
 1574     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1575     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
 1576     # check that stop(1) was called
 1577     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1578     # don't restore from ebp
 1579     81 0/subop/add %esp 8/imm32
 1580     5d/pop-to-ebp
 1581     c3/return
 1582 
 1583 test-convert-function-call-with-inout-with-incorrect-compound-type:
 1584     # . prologue
 1585     55/push-ebp
 1586     89/<- %ebp 4/r32/esp
 1587     # setup
 1588     (clear-stream _test-input-stream)
 1589     (clear-stream $_test-input-buffered-file->buffer)
 1590     (clear-stream _test-output-stream)
 1591     (clear-stream $_test-output-buffered-file->buffer)
 1592     (clear-stream _test-error-stream)
 1593     (clear-stream $_test-error-buffered-file->buffer)
 1594     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1595     68/push 0/imm32
 1596     68/push 0/imm32
 1597     89/<- %edx 4/r32/esp
 1598     (tailor-exit-descriptor %edx 0x10)
 1599     #
 1600     (write _test-input-stream "fn f {\n")
 1601     (write _test-input-stream "  var x: (addr int)\n")
 1602     (write _test-input-stream "  g x\n")
 1603     (write _test-input-stream "}\n")
 1604     (write _test-input-stream "fn g a: (addr bool) {\n")
 1605     (write _test-input-stream "}\n")
 1606     # convert
 1607     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1608     # registers except esp clobbered at this point
 1609     # restore ed
 1610     89/<- %edx 4/r32/esp
 1611     (flush _test-output-buffered-file)
 1612     (flush _test-error-buffered-file)
 1613 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1619     # check output
 1620     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
 1621     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: error message")
 1622     # don't restore from ebp
 1623     81 0/subop/add %esp 8/imm32
 1624     # . epilogue
 1625     5d/pop-to-ebp
 1626     c3/return
 1627 
 1628 test-convert-function-call-with-inout-with-multiple-type-parameters:
 1629     # . prologue
 1630     55/push-ebp
 1631     89/<- %ebp 4/r32/esp
 1632     # setup
 1633     (clear-stream _test-input-stream)
 1634     (clear-stream $_test-input-buffered-file->buffer)
 1635     (clear-stream _test-output-stream)
 1636     (clear-stream $_test-output-buffered-file->buffer)
 1637     (clear-stream _test-error-stream)
 1638     (clear-stream $_test-error-buffered-file->buffer)
 1639     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1640     68/push 0/imm32
 1641     68/push 0/imm32
 1642     89/<- %edx 4/r32/esp
 1643     (tailor-exit-descriptor %edx 0x10)
 1644     #
 1645     (write _test-input-stream "fn f {\n")
 1646     (write _test-input-stream "  var x: (addr int)\n")
 1647     (write _test-input-stream "  var y: (addr int)\n")
 1648     (write _test-input-stream "  g x, y\n")
 1649     (write _test-input-stream "}\n")
 1650     (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
 1651     (write _test-input-stream "}\n")
 1652     # convert
 1653     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1654     # registers except esp clobbered at this point
 1655     # restore ed
 1656     89/<- %edx 4/r32/esp
 1657     (flush _test-output-buffered-file)
 1658     (flush _test-error-buffered-file)
 1659 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1665     # no errors
 1666     (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
 1667     # don't bother checking the generated code
 1668     # don't restore from ebp
 1669     81 0/subop/add %esp 8/imm32
 1670     # . epilogue
 1671     5d/pop-to-ebp
 1672     c3/return
 1673 
 1674 test-type-parameter-matches-rest-of-type:
 1675     # . prologue
 1676     55/push-ebp
 1677     89/<- %ebp 4/r32/esp
 1678     # setup
 1679     (clear-stream _test-input-stream)
 1680     (clear-stream $_test-input-buffered-file->buffer)
 1681     (clear-stream _test-output-stream)
 1682     (clear-stream $_test-output-buffered-file->buffer)
 1683     (clear-stream _test-error-stream)
 1684     (clear-stream $_test-error-buffered-file->buffer)
 1685     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1686     68/push 0/imm32
 1687     68/push 0/imm32
 1688     89/<- %edx 4/r32/esp
 1689     (tailor-exit-descriptor %edx 0x10)
 1690     #
 1691     (write _test-input-stream "fn f {\n")
 1692     (write _test-input-stream "  var x: (addr array int)\n")
 1693     (write _test-input-stream "  g x\n")
 1694     (write _test-input-stream "}\n")
 1695     (write _test-input-stream "fn g a: (addr _) {\n")
 1696     (write _test-input-stream "}\n")
 1697     # convert
 1698     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1699     # registers except esp clobbered at this point
 1700     # restore ed
 1701     89/<- %edx 4/r32/esp
 1702     (flush _test-output-buffered-file)
 1703     (flush _test-error-buffered-file)
 1704 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1710     # no errors
 1711     (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
 1712     # don't bother checking the generated code
 1713     # don't restore from ebp
 1714     81 0/subop/add %esp 8/imm32
 1715     # . epilogue
 1716     5d/pop-to-ebp
 1717     c3/return
 1718 
 1719 test-convert-function-call-with-inout-with-incompatible-type-parameters:
 1720     # . prologue
 1721     55/push-ebp
 1722     89/<- %ebp 4/r32/esp
 1723     # setup
 1724     (clear-stream _test-input-stream)
 1725     (clear-stream $_test-input-buffered-file->buffer)
 1726     (clear-stream _test-output-stream)
 1727     (clear-stream $_test-output-buffered-file->buffer)
 1728     (clear-stream _test-error-stream)
 1729     (clear-stream $_test-error-buffered-file->buffer)
 1730     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1731     68/push 0/imm32
 1732     68/push 0/imm32
 1733     89/<- %edx 4/r32/esp
 1734     (tailor-exit-descriptor %edx 0x10)
 1735     #
 1736     (write _test-input-stream "fn f {\n")
 1737     (write _test-input-stream "  var x: (addr int)\n")
 1738     (write _test-input-stream "  var y: (addr boolean)\n")
 1739     (write _test-input-stream "  g x, y\n")
 1740     (write _test-input-stream "}\n")
 1741     (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
 1742     (write _test-input-stream "}\n")
 1743     # convert
 1744     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1745     # registers except esp clobbered at this point
 1746     # restore ed
 1747     89/<- %edx 4/r32/esp
 1748     (flush _test-output-buffered-file)
 1749     (flush _test-error-buffered-file)
 1750 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1756     # check output
 1757     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
 1758     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'y' is not right"  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: error message")
 1759     # don't restore from ebp
 1760     81 0/subop/add %esp 8/imm32
 1761     # . epilogue
 1762     5d/pop-to-ebp
 1763     c3/return
 1764 
 1765 test-convert-function-call-with-too-few-inouts:
 1766     # . prologue
 1767     55/push-ebp
 1768     89/<- %ebp 4/r32/esp
 1769     # setup
 1770     (clear-stream _test-input-stream)
 1771     (clear-stream $_test-input-buffered-file->buffer)
 1772     (clear-stream _test-output-stream)
 1773     (clear-stream $_test-output-buffered-file->buffer)
 1774     (clear-stream _test-error-stream)
 1775     (clear-stream $_test-error-buffered-file->buffer)
 1776     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1777     68/push 0/imm32
 1778     68/push 0/imm32
 1779     89/<- %edx 4/r32/esp
 1780     (tailor-exit-descriptor %edx 0x10)
 1781     #
 1782     (write _test-input-stream "fn f {\n")
 1783     (write _test-input-stream "  g\n")
 1784     (write _test-input-stream "}\n")
 1785     (write _test-input-stream "fn g a: int {\n")
 1786     (write _test-input-stream "}\n")
 1787     # convert
 1788     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1789     # registers except esp clobbered at this point
 1790     # restore ed
 1791     89/<- %edx 4/r32/esp
 1792     (flush _test-output-buffered-file)
 1793     (flush _test-error-buffered-file)
 1794 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1800     # check output
 1801     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1802     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few inouts"  "F - test-convert-function-call-with-too-few-inouts: error message")
 1803     # check that stop(1) was called
 1804     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1805     # don't restore from ebp
 1806     81 0/subop/add %esp 8/imm32
 1807     5d/pop-to-ebp
 1808     c3/return
 1809 
 1810 test-convert-function-call-with-too-many-inouts:
 1811     # . prologue
 1812     55/push-ebp
 1813     89/<- %ebp 4/r32/esp
 1814     # setup
 1815     (clear-stream _test-input-stream)
 1816     (clear-stream $_test-input-buffered-file->buffer)
 1817     (clear-stream _test-output-stream)
 1818     (clear-stream $_test-output-buffered-file->buffer)
 1819     (clear-stream _test-error-stream)
 1820     (clear-stream $_test-error-buffered-file->buffer)
 1821     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1822     68/push 0/imm32
 1823     68/push 0/imm32
 1824     89/<- %edx 4/r32/esp
 1825     (tailor-exit-descriptor %edx 0x10)
 1826     #
 1827     (write _test-input-stream "fn f {\n")
 1828     (write _test-input-stream "  var x: int\n")
 1829     (write _test-input-stream "  g x\n")
 1830     (write _test-input-stream "}\n")
 1831     (write _test-input-stream "fn g {\n")
 1832     (write _test-input-stream "}\n")
 1833     # convert
 1834     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1835     # registers except esp clobbered at this point
 1836     # restore ed
 1837     89/<- %edx 4/r32/esp
 1838     (flush _test-output-buffered-file)
 1839     (flush _test-error-buffered-file)
 1840 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1846     # check output
 1847     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1848     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many inouts"  "F - test-convert-function-call-with-too-many-inouts: error message")
 1849     # check that stop(1) was called
 1850     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1851     # don't restore from ebp
 1852     81 0/subop/add %esp 8/imm32
 1853     5d/pop-to-ebp
 1854     c3/return
 1855 
 1856 test-convert-function-call-with-incorrect-output-type:
 1857     # . prologue
 1858     55/push-ebp
 1859     89/<- %ebp 4/r32/esp
 1860     # setup
 1861     (clear-stream _test-input-stream)
 1862     (clear-stream $_test-input-buffered-file->buffer)
 1863     (clear-stream _test-output-stream)
 1864     (clear-stream $_test-output-buffered-file->buffer)
 1865     (clear-stream _test-error-stream)
 1866     (clear-stream $_test-error-buffered-file->buffer)
 1867     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1868     68/push 0/imm32
 1869     68/push 0/imm32
 1870     89/<- %edx 4/r32/esp
 1871     (tailor-exit-descriptor %edx 0x10)
 1872     #
 1873     (write _test-input-stream "fn f {\n")
 1874     (write _test-input-stream "  var x/eax: int <- g\n")
 1875     (write _test-input-stream "}\n")
 1876     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1877     (write _test-input-stream "}\n")
 1878     # convert
 1879     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1880     # registers except esp clobbered at this point
 1881     # restore ed
 1882     89/<- %edx 4/r32/esp
 1883     (flush _test-output-buffered-file)
 1884     (flush _test-error-buffered-file)
 1885 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1891     # check output
 1892     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1893     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-type: error message")
 1894     # check that stop(1) was called
 1895     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1896     # don't restore from ebp
 1897     81 0/subop/add %esp 8/imm32
 1898     5d/pop-to-ebp
 1899     c3/return
 1900 
 1901 test-convert-function-call-with-too-few-outputs:
 1902     # . prologue
 1903     55/push-ebp
 1904     89/<- %ebp 4/r32/esp
 1905     # setup
 1906     (clear-stream _test-input-stream)
 1907     (clear-stream $_test-input-buffered-file->buffer)
 1908     (clear-stream _test-output-stream)
 1909     (clear-stream $_test-output-buffered-file->buffer)
 1910     (clear-stream _test-error-stream)
 1911     (clear-stream $_test-error-buffered-file->buffer)
 1912     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1913     68/push 0/imm32
 1914     68/push 0/imm32
 1915     89/<- %edx 4/r32/esp
 1916     (tailor-exit-descriptor %edx 0x10)
 1917     #
 1918     (write _test-input-stream "fn f {\n")
 1919     (write _test-input-stream "  g\n")
 1920     (write _test-input-stream "}\n")
 1921     (write _test-input-stream "fn g -> a/eax: int {\n")
 1922     (write _test-input-stream "}\n")
 1923     # convert
 1924     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1925     # registers except esp clobbered at this point
 1926     # restore ed
 1927     89/<- %edx 4/r32/esp
 1928     (flush _test-output-buffered-file)
 1929     (flush _test-error-buffered-file)
 1930 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1936     # check output
 1937     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1938     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few outputs"  "F - test-convert-function-call-with-too-few-outputs: error message")
 1939     # check that stop(1) was called
 1940     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1941     # don't restore from ebp
 1942     81 0/subop/add %esp 8/imm32
 1943     5d/pop-to-ebp
 1944     c3/return
 1945 
 1946 test-convert-function-call-with-too-many-outputs:
 1947     # . prologue
 1948     55/push-ebp
 1949     89/<- %ebp 4/r32/esp
 1950     # setup
 1951     (clear-stream _test-input-stream)
 1952     (clear-stream $_test-input-buffered-file->buffer)
 1953     (clear-stream _test-output-stream)
 1954     (clear-stream $_test-output-buffered-file->buffer)
 1955     (clear-stream _test-error-stream)
 1956     (clear-stream $_test-error-buffered-file->buffer)
 1957     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1958     68/push 0/imm32
 1959     68/push 0/imm32
 1960     89/<- %edx 4/r32/esp
 1961     (tailor-exit-descriptor %edx 0x10)
 1962     #
 1963     (write _test-input-stream "fn f {\n")
 1964     (write _test-input-stream "  var x/eax: int <- g\n")
 1965     (write _test-input-stream "}\n")
 1966     (write _test-input-stream "fn g {\n")
 1967     (write _test-input-stream "}\n")
 1968     # convert
 1969     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1970     # registers except esp clobbered at this point
 1971     # restore ed
 1972     89/<- %edx 4/r32/esp
 1973     (flush _test-output-buffered-file)
 1974     (flush _test-error-buffered-file)
 1975 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1981     # check output
 1982     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1983     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many outputs"  "F - test-convert-function-call-with-too-many-outputs: error message")
 1984     # check that stop(1) was called
 1985     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1986     # don't restore from ebp
 1987     81 0/subop/add %esp 8/imm32
 1988     5d/pop-to-ebp
 1989     c3/return
 1990 
 1991 test-convert-function-call-with-missing-output-register:
 1992     # . prologue
 1993     55/push-ebp
 1994     89/<- %ebp 4/r32/esp
 1995     # setup
 1996     (clear-stream _test-input-stream)
 1997     (clear-stream $_test-input-buffered-file->buffer)
 1998     (clear-stream _test-output-stream)
 1999     (clear-stream $_test-output-buffered-file->buffer)
 2000     (clear-stream _test-error-stream)
 2001     (clear-stream $_test-error-buffered-file->buffer)
 2002     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2003     68/push 0/imm32
 2004     68/push 0/imm32
 2005     89/<- %edx 4/r32/esp
 2006     (tailor-exit-descriptor %edx 0x10)
 2007     #
 2008     (write _test-input-stream "fn f {\n")
 2009     (write _test-input-stream "  var x: int\n")
 2010     (write _test-input-stream "  x <- g\n")
 2011     (write _test-input-stream "}\n")
 2012     (write _test-input-stream "fn g -> a/eax: int {\n")
 2013     (write _test-input-stream "}\n")
 2014     # convert
 2015     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2016     # registers except esp clobbered at this point
 2017     # restore ed
 2018     89/<- %edx 4/r32/esp
 2019     (flush _test-output-buffered-file)
 2020     (flush _test-error-buffered-file)
 2021 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2027     # check output
 2028     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-missing-output-register: output should be empty")
 2029     (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")
 2030     # check that stop(1) was called
 2031     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-missing-output-register: exit status")
 2032     # don't restore from ebp
 2033     81 0/subop/add %esp 8/imm32
 2034     5d/pop-to-ebp
 2035     c3/return
 2036 
 2037 test-convert-function-call-with-incorrect-output-register:
 2038     # . prologue
 2039     55/push-ebp
 2040     89/<- %ebp 4/r32/esp
 2041     # setup
 2042     (clear-stream _test-input-stream)
 2043     (clear-stream $_test-input-buffered-file->buffer)
 2044     (clear-stream _test-output-stream)
 2045     (clear-stream $_test-output-buffered-file->buffer)
 2046     (clear-stream _test-error-stream)
 2047     (clear-stream $_test-error-buffered-file->buffer)
 2048     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2049     68/push 0/imm32
 2050     68/push 0/imm32
 2051     89/<- %edx 4/r32/esp
 2052     (tailor-exit-descriptor %edx 0x10)
 2053     #
 2054     (write _test-input-stream "fn f {\n")
 2055     (write _test-input-stream "  var x/ecx: int <- g\n")
 2056     (write _test-input-stream "}\n")
 2057     (write _test-input-stream "fn g -> a/eax: int {\n")
 2058     (write _test-input-stream "}\n")
 2059     # convert
 2060     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2061     # registers except esp clobbered at this point
 2062     # restore ed
 2063     89/<- %edx 4/r32/esp
 2064     (flush _test-output-buffered-file)
 2065     (flush _test-error-buffered-file)
 2066 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2072     # check output
 2073     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 2074     (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")
 2075     # check that stop(1) was called
 2076     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 2077     # don't restore from ebp
 2078     81 0/subop/add %esp 8/imm32
 2079     5d/pop-to-ebp
 2080     c3/return
 2081 
 2082 test-convert-function-with-local-var-dereferenced:
 2083     # . prologue
 2084     55/push-ebp
 2085     89/<- %ebp 4/r32/esp
 2086     # setup
 2087     (clear-stream _test-input-stream)
 2088     (clear-stream $_test-input-buffered-file->buffer)
 2089     (clear-stream _test-output-stream)
 2090     (clear-stream $_test-output-buffered-file->buffer)
 2091     #
 2092     (write _test-input-stream "fn foo {\n")
 2093     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 2094     (write _test-input-stream "  increment *x\n")
 2095     (write _test-input-stream "}\n")
 2096     # convert
 2097     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2098     (flush _test-output-buffered-file)
 2099 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2105     # check output
 2106     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 2107     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 2108     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 2109     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 2110     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 2111     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 2112     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 2113     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 2114     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 2115     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 2116     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 2117     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 2118     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 2119     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 2120     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 2121     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 2122     # . epilogue
 2123     89/<- %esp 5/r32/ebp
 2124     5d/pop-to-ebp
 2125     c3/return
 2126 
 2127 # variables of type 'byte' are not allowed on the stack
 2128 test-convert-function-with-byte-operations:
 2129     # . prologue
 2130     55/push-ebp
 2131     89/<- %ebp 4/r32/esp
 2132     # setup
 2133     (clear-stream _test-input-stream)
 2134     (clear-stream $_test-input-buffered-file->buffer)
 2135     (clear-stream _test-output-stream)
 2136     (clear-stream $_test-output-buffered-file->buffer)
 2137     #
 2138     (write _test-input-stream "fn foo {\n")
 2139     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 2140     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 2141     (write _test-input-stream "  y <- copy-byte x\n")
 2142     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 2143     (write _test-input-stream "  y <- copy-byte *z\n")
 2144     (write _test-input-stream "  copy-byte-to *z, x\n")
 2145     (write _test-input-stream "}\n")
 2146     # convert
 2147     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2148     (flush _test-output-buffered-file)
 2149 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2155     # check output
 2156     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 2157     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 2158     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 2159     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 2160     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 2161     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 2162     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 2163     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 2164     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 2165     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 2166     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 2167     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 2168     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 2169     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 2170     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 2171     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 2172     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 2173     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 2174     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 2175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 2176     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 2177     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 2178     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 2179     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 2180     # . epilogue
 2181     89/<- %esp 5/r32/ebp
 2182     5d/pop-to-ebp
 2183     c3/return
 2184 
 2185 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 2186 test-copy-byte-var-from-fn-arg:
 2187     # . prologue
 2188     55/push-ebp
 2189     89/<- %ebp 4/r32/esp
 2190     # setup
 2191     (clear-stream _test-input-stream)
 2192     (clear-stream $_test-input-buffered-file->buffer)
 2193     (clear-stream _test-output-stream)
 2194     (clear-stream $_test-output-buffered-file->buffer)
 2195     #
 2196     (write _test-input-stream "fn foo x: byte, y: int {\n")
 2197     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 2198     (write _test-input-stream "  var b/eax: int <- copy y\n")
 2199     (write _test-input-stream "}\n")
 2200     # convert
 2201     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2202     (flush _test-output-buffered-file)
 2203 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2209     # check output
 2210     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 2211     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 2212     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 2213     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 2214     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 2215     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 2216     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 2217     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 2218     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 2219     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 2220     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 2221     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 2222     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 2223     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 2224     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 2225     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 2226     # . epilogue
 2227     89/<- %esp 5/r32/ebp
 2228     5d/pop-to-ebp
 2229     c3/return
 2230 
 2231 test-convert-compare-register-with-literal:
 2232     # . prologue
 2233     55/push-ebp
 2234     89/<- %ebp 4/r32/esp
 2235     # setup
 2236     (clear-stream _test-input-stream)
 2237     (clear-stream $_test-input-buffered-file->buffer)
 2238     (clear-stream _test-output-stream)
 2239     (clear-stream $_test-output-buffered-file->buffer)
 2240     #
 2241     (write _test-input-stream "fn foo {\n")
 2242     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 2243     (write _test-input-stream "  compare x, 0\n")
 2244     (write _test-input-stream "}\n")
 2245     # convert
 2246     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2247     (flush _test-output-buffered-file)
 2248 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2254     # check output
 2255     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 2256     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 2257     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 2258     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 2259     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 2260     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 2261     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2262     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 2263     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 2264     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2265     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 2266     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 2267     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 2268     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 2269     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 2270     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 2271     # . epilogue
 2272     89/<- %esp 5/r32/ebp
 2273     5d/pop-to-ebp
 2274     c3/return
 2275 
 2276 test-unknown-variable:
 2277     # . prologue
 2278     55/push-ebp
 2279     89/<- %ebp 4/r32/esp
 2280     # setup
 2281     (clear-stream _test-input-stream)
 2282     (clear-stream $_test-input-buffered-file->buffer)
 2283     (clear-stream _test-output-stream)
 2284     (clear-stream $_test-output-buffered-file->buffer)
 2285     (clear-stream _test-error-stream)
 2286     (clear-stream $_test-error-buffered-file->buffer)
 2287     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2288     68/push 0/imm32
 2289     68/push 0/imm32
 2290     89/<- %edx 4/r32/esp
 2291     (tailor-exit-descriptor %edx 0x10)
 2292     #
 2293     (write _test-input-stream "fn foo {\n")
 2294     (write _test-input-stream "  compare x, 0\n")
 2295     (write _test-input-stream "}\n")
 2296     # convert
 2297     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2298     # registers except esp clobbered at this point
 2299     # restore ed
 2300     89/<- %edx 4/r32/esp
 2301     (flush _test-output-buffered-file)
 2302     (flush _test-error-buffered-file)
 2303 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2309     # check output
 2310     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 2311     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 2312     # check that stop(1) was called
 2313     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 2314     # don't restore from ebp
 2315     81 0/subop/add %esp 8/imm32
 2316     # . epilogue
 2317     5d/pop-to-ebp
 2318     c3/return
 2319 
 2320 test-convert-function-with-local-var-in-block:
 2321     # . prologue
 2322     55/push-ebp
 2323     89/<- %ebp 4/r32/esp
 2324     # setup
 2325     (clear-stream _test-input-stream)
 2326     (clear-stream $_test-input-buffered-file->buffer)
 2327     (clear-stream _test-output-stream)
 2328     (clear-stream $_test-output-buffered-file->buffer)
 2329     #
 2330     (write _test-input-stream "fn foo {\n")
 2331     (write _test-input-stream "  {\n")
 2332     (write _test-input-stream "    var x: int\n")
 2333     (write _test-input-stream "    increment x\n")
 2334     (write _test-input-stream "  }\n")
 2335     (write _test-input-stream "}\n")
 2336     # convert
 2337     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2338     (flush _test-output-buffered-file)
 2339 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2345     # check output
 2346     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 2347     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 2348     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 2349     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 2350     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 2351     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 2352     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 2353     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 2354     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 2355     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 2356     (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")
 2357     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 2358     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 2359     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 2360     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 2361     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 2362     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 2363     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 2364     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 2365     # . epilogue
 2366     89/<- %esp 5/r32/ebp
 2367     5d/pop-to-ebp
 2368     c3/return
 2369 
 2370 test-convert-function-with-local-var-in-mem-after-block:
 2371     # . prologue
 2372     55/push-ebp
 2373     89/<- %ebp 4/r32/esp
 2374     # setup
 2375     (clear-stream _test-input-stream)
 2376     (clear-stream $_test-input-buffered-file->buffer)
 2377     (clear-stream _test-output-stream)
 2378     (clear-stream $_test-output-buffered-file->buffer)
 2379     #
 2380     (write _test-input-stream "fn foo {\n")
 2381     (write _test-input-stream "  {\n")
 2382     (write _test-input-stream "    var y: int\n")
 2383     (write _test-input-stream "  }\n")
 2384     (write _test-input-stream "  var x: int\n")
 2385     (write _test-input-stream "  increment x\n")
 2386     (write _test-input-stream "}\n")
 2387     # convert
 2388     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2389     (flush _test-output-buffered-file)
 2390 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2396     # check output
 2397     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem-after-block/0")
 2398     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem-after-block/1")
 2399     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem-after-block/2")
 2400     (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")
 2401     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem-after-block/4")
 2402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/5")
 2403     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-mem-after-block/6")
 2404     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/7")
 2405     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-mem-after-block/8")
 2406     (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")
 2407     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-mem-after-block/10")
 2408     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/11")
 2409     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem-after-block/12")
 2410     (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")
 2411     (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")
 2412     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem-after-block/15")
 2413     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/16")
 2414     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem-after-block/17")
 2415     (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")
 2416     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem-after-block/19")
 2417     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem-after-block/20")
 2418     # . epilogue
 2419     89/<- %esp 5/r32/ebp
 2420     5d/pop-to-ebp
 2421     c3/return
 2422 
 2423 test-convert-function-with-local-var-in-named-block:
 2424     # . prologue
 2425     55/push-ebp
 2426     89/<- %ebp 4/r32/esp
 2427     # setup
 2428     (clear-stream _test-input-stream)
 2429     (clear-stream $_test-input-buffered-file->buffer)
 2430     (clear-stream _test-output-stream)
 2431     (clear-stream $_test-output-buffered-file->buffer)
 2432     #
 2433     (write _test-input-stream "fn foo {\n")
 2434     (write _test-input-stream "  $bar: {\n")
 2435     (write _test-input-stream "    var x: int\n")
 2436     (write _test-input-stream "    increment x\n")
 2437     (write _test-input-stream "  }\n")
 2438     (write _test-input-stream "}\n")
 2439     # convert
 2440     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2441     (flush _test-output-buffered-file)
 2442 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2448     # check output
 2449     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 2450     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 2451     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 2452     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 2453     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 2454     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 2455     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 2456     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 2457     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 2458     (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")
 2459     (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")
 2460     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 2461     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 2462     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 2463     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 2464     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 2465     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 2466     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 2467     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 2468     # . epilogue
 2469     89/<- %esp 5/r32/ebp
 2470     5d/pop-to-ebp
 2471     c3/return
 2472 
 2473 test-unknown-variable-in-named-block:
 2474     # . prologue
 2475     55/push-ebp
 2476     89/<- %ebp 4/r32/esp
 2477     # setup
 2478     (clear-stream _test-input-stream)
 2479     (clear-stream $_test-input-buffered-file->buffer)
 2480     (clear-stream _test-output-stream)
 2481     (clear-stream $_test-output-buffered-file->buffer)
 2482     (clear-stream _test-error-stream)
 2483     (clear-stream $_test-error-buffered-file->buffer)
 2484     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2485     68/push 0/imm32
 2486     68/push 0/imm32
 2487     89/<- %edx 4/r32/esp
 2488     (tailor-exit-descriptor %edx 0x10)
 2489     #
 2490     (write _test-input-stream "fn foo {\n")
 2491     (write _test-input-stream "  $a: {\n")
 2492     (write _test-input-stream "    compare x, 0\n")
 2493     (write _test-input-stream "  }\n")
 2494     (write _test-input-stream "}\n")
 2495     # convert
 2496     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2497     # registers except esp clobbered at this point
 2498     # restore ed
 2499     89/<- %edx 4/r32/esp
 2500     (flush _test-output-buffered-file)
 2501     (flush _test-error-buffered-file)
 2502 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2508     # check output
 2509     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 2510     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 2511     # check that stop(1) was called
 2512     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 2513     # don't restore from ebp
 2514     81 0/subop/add %esp 8/imm32
 2515     # . epilogue
 2516     5d/pop-to-ebp
 2517     c3/return
 2518 
 2519 test-always-shadow-outermost-reg-vars-in-function:
 2520     # . prologue
 2521     55/push-ebp
 2522     89/<- %ebp 4/r32/esp
 2523     # setup
 2524     (clear-stream _test-input-stream)
 2525     (clear-stream $_test-input-buffered-file->buffer)
 2526     (clear-stream _test-output-stream)
 2527     (clear-stream $_test-output-buffered-file->buffer)
 2528     #
 2529     (write _test-input-stream "fn foo {\n")
 2530     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2531     (write _test-input-stream "}\n")
 2532     # convert
 2533     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2534     (flush _test-output-buffered-file)
 2535 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2541     # check output
 2542     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2543     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2544     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2545     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2546     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2547     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2548     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2549     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2550     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2551     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2552     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2553     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2554     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2555     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2556     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2557     # . epilogue
 2558     89/<- %esp 5/r32/ebp
 2559     5d/pop-to-ebp
 2560     c3/return
 2561 
 2562 _pending-test-clobber-dead-local:
 2563     # . prologue
 2564     55/push-ebp
 2565     89/<- %ebp 4/r32/esp
 2566     # setup
 2567     (clear-stream _test-input-stream)
 2568     (clear-stream $_test-input-buffered-file->buffer)
 2569     (clear-stream _test-output-stream)
 2570     (clear-stream $_test-output-buffered-file->buffer)
 2571     #
 2572     (write _test-input-stream "fn foo {\n")
 2573     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2574     (write _test-input-stream "  {\n")
 2575     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2576     (write _test-input-stream "  }\n")
 2577     (write _test-input-stream "}\n")
 2578     # convert
 2579     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2580     (flush _test-output-buffered-file)
 2581 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2587     # check output
 2588     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2589     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2590     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2591     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2592     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2593     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2594     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2595     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2596     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2597     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2598     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2599     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2600     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2601     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2602     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2604     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2605     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2606     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2607     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2608     # . epilogue
 2609     89/<- %esp 5/r32/ebp
 2610     5d/pop-to-ebp
 2611     c3/return
 2612 
 2613 test-shadow-live-local:
 2614     # . prologue
 2615     55/push-ebp
 2616     89/<- %ebp 4/r32/esp
 2617     # setup
 2618     (clear-stream _test-input-stream)
 2619     (clear-stream $_test-input-buffered-file->buffer)
 2620     (clear-stream _test-output-stream)
 2621     (clear-stream $_test-output-buffered-file->buffer)
 2622     #
 2623     (write _test-input-stream "fn foo {\n")
 2624     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2625     (write _test-input-stream "  {\n")
 2626     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2627     (write _test-input-stream "  }\n")
 2628     (write _test-input-stream "  x <- increment\n")
 2629     (write _test-input-stream "}\n")
 2630     # convert
 2631     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2632     (flush _test-output-buffered-file)
 2633 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2639     # check output
 2640     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2641     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2642     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2643     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2644     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2645     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2646     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2647     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2648     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2649     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2650     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2651     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2652     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2653     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2654     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2655     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2656     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2657     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2658     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2659     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2660     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2661     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2662     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2663     # . epilogue
 2664     89/<- %esp 5/r32/ebp
 2665     5d/pop-to-ebp
 2666     c3/return
 2667 
 2668 test-shadow-name:
 2669     # . prologue
 2670     55/push-ebp
 2671     89/<- %ebp 4/r32/esp
 2672     # setup
 2673     (clear-stream _test-input-stream)
 2674     (clear-stream $_test-input-buffered-file->buffer)
 2675     (clear-stream _test-output-stream)
 2676     (clear-stream $_test-output-buffered-file->buffer)
 2677     #
 2678     (write _test-input-stream "fn foo {\n")
 2679     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2680     (write _test-input-stream "  {\n")
 2681     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2682     (write _test-input-stream "  }\n")
 2683     (write _test-input-stream "  x <- increment\n")
 2684     (write _test-input-stream "}\n")
 2685     # convert
 2686     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2687     (flush _test-output-buffered-file)
 2688 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2694     # check output
 2695     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2696     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2697     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2698     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2699     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2700     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2701     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2702     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2703     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2704     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2705     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2706     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2707     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2708     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2710     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2711     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2712     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2714     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2715     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2716     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2717     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2718     # . epilogue
 2719     89/<- %esp 5/r32/ebp
 2720     5d/pop-to-ebp
 2721     c3/return
 2722 
 2723 test-shadow-name-2:
 2724     # . prologue
 2725     55/push-ebp
 2726     89/<- %ebp 4/r32/esp
 2727     # setup
 2728     (clear-stream _test-input-stream)
 2729     (clear-stream $_test-input-buffered-file->buffer)
 2730     (clear-stream _test-output-stream)
 2731     (clear-stream $_test-output-buffered-file->buffer)
 2732     #
 2733     (write _test-input-stream "fn foo {\n")
 2734     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2735     (write _test-input-stream "  {\n")
 2736     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2737     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2738     (write _test-input-stream "  }\n")
 2739     (write _test-input-stream "  x <- increment\n")
 2740     (write _test-input-stream "}\n")
 2741     # convert
 2742     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2743     (flush _test-output-buffered-file)
 2744 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2750     # check output
 2751     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2752     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2753     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2754     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2755     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2756     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2757     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2758     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2759     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2760     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2761     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2762     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2763     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2764     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2765     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2766     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2767     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2768     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2769     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2770     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2771     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2772     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2773     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2774     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2775     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2776     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2777     # . epilogue
 2778     89/<- %esp 5/r32/ebp
 2779     5d/pop-to-ebp
 2780     c3/return
 2781 
 2782 test-do-not-spill-same-register-in-block:
 2783     # . prologue
 2784     55/push-ebp
 2785     89/<- %ebp 4/r32/esp
 2786     # setup
 2787     (clear-stream _test-input-stream)
 2788     (clear-stream $_test-input-buffered-file->buffer)
 2789     (clear-stream _test-output-stream)
 2790     (clear-stream $_test-output-buffered-file->buffer)
 2791     #
 2792     (write _test-input-stream "fn foo {\n")
 2793     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2794     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2795     (write _test-input-stream "  y <- increment\n")
 2796     (write _test-input-stream "}\n")
 2797     # convert
 2798     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2799     (flush _test-output-buffered-file)
 2800 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2806     # check output
 2807     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2808     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2809     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2810     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2811     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2812     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2813     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2814     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2815     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2816     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2817     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2818     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2820     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2821     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2822     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2823     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2824     # . epilogue
 2825     89/<- %esp 5/r32/ebp
 2826     5d/pop-to-ebp
 2827     c3/return
 2828 
 2829 test-spill-different-register-in-block:
 2830     # . prologue
 2831     55/push-ebp
 2832     89/<- %ebp 4/r32/esp
 2833     # setup
 2834     (clear-stream _test-input-stream)
 2835     (clear-stream $_test-input-buffered-file->buffer)
 2836     (clear-stream _test-output-stream)
 2837     (clear-stream $_test-output-buffered-file->buffer)
 2838     #
 2839     (write _test-input-stream "fn foo {\n")
 2840     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2841     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2842     (write _test-input-stream "  y <- increment\n")
 2843     (write _test-input-stream "}\n")
 2844     # convert
 2845     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2846     (flush _test-output-buffered-file)
 2847 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2853     # check output
 2854     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2855     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2856     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2857     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2858     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2859     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2860     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2861     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2862     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2863     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2864     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2865     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2866     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2867     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2868     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2869     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2870     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2871     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2872     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2873     # . epilogue
 2874     89/<- %esp 5/r32/ebp
 2875     5d/pop-to-ebp
 2876     c3/return
 2877 
 2878 test-shadow-live-output:
 2879     # . prologue
 2880     55/push-ebp
 2881     89/<- %ebp 4/r32/esp
 2882     # setup
 2883     (clear-stream _test-input-stream)
 2884     (clear-stream $_test-input-buffered-file->buffer)
 2885     (clear-stream _test-output-stream)
 2886     (clear-stream $_test-output-buffered-file->buffer)
 2887     #
 2888     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2889     (write _test-input-stream "  x <- copy 3\n")
 2890     (write _test-input-stream "  {\n")
 2891     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2892     (write _test-input-stream "  }\n")
 2893     (write _test-input-stream "  x <- increment\n")
 2894     (write _test-input-stream "}\n")
 2895     # convert
 2896     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2897     (flush _test-output-buffered-file)
 2898 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2904     # check output
 2905     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2906     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2907     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2908     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2909     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2910     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2911     (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
 2912     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2913     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2914     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2915     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2916     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2917     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2918     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2919     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2920     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2921     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2922     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2923     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2924     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2925     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2926     # . epilogue
 2927     89/<- %esp 5/r32/ebp
 2928     5d/pop-to-ebp
 2929     c3/return
 2930 
 2931 test-stmt-defines-output-in-same-register-as-inout:
 2932     # . prologue
 2933     55/push-ebp
 2934     89/<- %ebp 4/r32/esp
 2935     # setup
 2936     (clear-stream _test-input-stream)
 2937     (clear-stream $_test-input-buffered-file->buffer)
 2938     (clear-stream _test-output-stream)
 2939     (clear-stream $_test-output-buffered-file->buffer)
 2940     (clear-stream _test-error-stream)
 2941     (clear-stream $_test-error-buffered-file->buffer)
 2942     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2943     68/push 0/imm32
 2944     68/push 0/imm32
 2945     89/<- %edx 4/r32/esp
 2946     (tailor-exit-descriptor %edx 0x10)
 2947     #
 2948     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2949     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2950     (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
 2951     (write _test-input-stream "}\n")
 2952     # convert
 2953     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2954     # registers except esp clobbered at this point
 2955     # restore ed
 2956     89/<- %edx 4/r32/esp
 2957     (flush _test-output-buffered-file)
 2958     (flush _test-error-buffered-file)
 2959 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2965     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2966     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2967     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2968     # don't restore from ebp
 2969     81 0/subop/add %esp 8/imm32
 2970     # . epilogue
 2971     5d/pop-to-ebp
 2972     c3/return
 2973 
 2974 test-local-clobbered-by-fn-output:
 2975     # . prologue
 2976     55/push-ebp
 2977     89/<- %ebp 4/r32/esp
 2978     # setup
 2979     (clear-stream _test-input-stream)
 2980     (clear-stream $_test-input-buffered-file->buffer)
 2981     (clear-stream _test-output-stream)
 2982     (clear-stream $_test-output-buffered-file->buffer)
 2983     #
 2984     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2985     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2986     (write _test-input-stream "  x <- copy y\n")
 2987     (write _test-input-stream "}\n")
 2988     # convert
 2989     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2990     (flush _test-output-buffered-file)
 2991 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 2997     # check output
 2998     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2999     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 3000     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 3001     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 3002     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 3003     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 3004     (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
 3005     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 3006     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 3007     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 3008     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 3009     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 3010     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 3011     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 3012     # . epilogue
 3013     89/<- %esp 5/r32/ebp
 3014     5d/pop-to-ebp
 3015     c3/return
 3016 
 3017 test-read-output:
 3018     # . prologue
 3019     55/push-ebp
 3020     89/<- %ebp 4/r32/esp
 3021     # setup
 3022     (clear-stream _test-input-stream)
 3023     (clear-stream $_test-input-buffered-file->buffer)
 3024     (clear-stream _test-output-stream)
 3025     (clear-stream $_test-output-buffered-file->buffer)
 3026     #
 3027     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 3028     (write _test-input-stream "  x <- copy 0x34\n")
 3029     (write _test-input-stream "  compare x, 0x35\n")
 3030     (write _test-input-stream "}\n")
 3031     # convert
 3032     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3033     (flush _test-output-buffered-file)
 3034 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3040     # check output
 3041     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 3042     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 3043     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 3044     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 3045     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 3046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 3047     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 3048     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 3049     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 3050     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 3051     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 3052     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 3053     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 3054     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 3055     # . epilogue
 3056     89/<- %esp 5/r32/ebp
 3057     5d/pop-to-ebp
 3058     c3/return
 3059 
 3060 test-fn-output-written-in-inner-block:
 3061     # . prologue
 3062     55/push-ebp
 3063     89/<- %ebp 4/r32/esp
 3064     # setup
 3065     (clear-stream _test-input-stream)
 3066     (clear-stream $_test-input-buffered-file->buffer)
 3067     (clear-stream _test-output-stream)
 3068     (clear-stream $_test-output-buffered-file->buffer)
 3069     #
 3070     (write _test-input-stream "fn foo -> out/edi: int {\n")
 3071     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 3072     (write _test-input-stream "  {\n")
 3073     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 3074     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 3075     (write _test-input-stream "  }\n")
 3076     (write _test-input-stream "  compare a, 0\n")  # use outer local
 3077     (write _test-input-stream "}\n")
 3078     # convert
 3079     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3080     (flush _test-output-buffered-file)
 3081 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3087     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 3088     # check output
 3089     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 3090     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 3091     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 3092     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 3093     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 3094     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 3095     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 3096     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 3097     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 3098     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 3099     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 3100     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 3101     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 3102     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 3103     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 3104     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 3105     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 3106     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 3107     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 3108     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 3109     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 3110     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 3111     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 3112     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 3113     # . epilogue
 3114     89/<- %esp 5/r32/ebp
 3115     5d/pop-to-ebp
 3116     c3/return
 3117 
 3118 test-convert-function-with-branches-in-block:
 3119     # . prologue
 3120     55/push-ebp
 3121     89/<- %ebp 4/r32/esp
 3122     # setup
 3123     (clear-stream _test-input-stream)
 3124     (clear-stream $_test-input-buffered-file->buffer)
 3125     (clear-stream _test-output-stream)
 3126     (clear-stream $_test-output-buffered-file->buffer)
 3127     #
 3128     (write _test-input-stream "fn foo x: int {\n")
 3129     (write _test-input-stream "  {\n")
 3130     (write _test-input-stream "    break-if->=\n")
 3131     (write _test-input-stream "    loop-if-addr<\n")
 3132     (write _test-input-stream "    increment x\n")
 3133     (write _test-input-stream "    loop\n")
 3134     (write _test-input-stream "  }\n")
 3135     (write _test-input-stream "}\n")
 3136     # convert
 3137     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3138     (flush _test-output-buffered-file)
 3139 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3145     # check output
 3146     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 3147     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 3148     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 3149     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 3150     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 3151     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 3152     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 3153     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 3154     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 3155     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 3156     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 3157     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 3158     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 3159     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 3160     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 3161     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 3162     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 3163     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 3164     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 3165     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 3166     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 3167     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 3168     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 3169     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 3170     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 3171     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 3172     # . epilogue
 3173     89/<- %esp 5/r32/ebp
 3174     5d/pop-to-ebp
 3175     c3/return
 3176 
 3177 test-convert-function-with-branches-in-named-block:
 3178     # . prologue
 3179     55/push-ebp
 3180     89/<- %ebp 4/r32/esp
 3181     # setup
 3182     (clear-stream _test-input-stream)
 3183     (clear-stream $_test-input-buffered-file->buffer)
 3184     (clear-stream _test-output-stream)
 3185     (clear-stream $_test-output-buffered-file->buffer)
 3186     #
 3187     (write _test-input-stream "fn foo x: int {\n")
 3188     (write _test-input-stream "  $bar: {\n")
 3189     (write _test-input-stream "    break-if->= $bar\n")
 3190     (write _test-input-stream "    loop-if-addr< $bar\n")
 3191     (write _test-input-stream "    increment x\n")
 3192     (write _test-input-stream "    loop\n")
 3193     (write _test-input-stream "  }\n")
 3194     (write _test-input-stream "}\n")
 3195     # convert
 3196     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3197     (flush _test-output-buffered-file)
 3198 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3204     # check output
 3205     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 3206     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 3207     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 3208     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 3209     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 3210     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 3211     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 3212     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 3213     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 3214     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 3215     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 3216     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 3217     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 3218     (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")
 3219     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 3220     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 3221     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 3222     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 3223     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 3224     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 3225     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 3226     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 3227     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 3228     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 3229     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 3230     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 3231     # . epilogue
 3232     89/<- %esp 5/r32/ebp
 3233     5d/pop-to-ebp
 3234     c3/return
 3235 
 3236 test-convert-function-with-var-in-nested-block:
 3237     # . prologue
 3238     55/push-ebp
 3239     89/<- %ebp 4/r32/esp
 3240     # setup
 3241     (clear-stream _test-input-stream)
 3242     (clear-stream $_test-input-buffered-file->buffer)
 3243     (clear-stream _test-output-stream)
 3244     (clear-stream $_test-output-buffered-file->buffer)
 3245     #
 3246     (write _test-input-stream "fn foo x: int {\n")
 3247     (write _test-input-stream "  {\n")
 3248     (write _test-input-stream "    {\n")
 3249     (write _test-input-stream "      var x: int\n")
 3250     (write _test-input-stream "      increment x\n")
 3251     (write _test-input-stream "    }\n")
 3252     (write _test-input-stream "  }\n")
 3253     (write _test-input-stream "}\n")
 3254     # convert
 3255     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3256     (flush _test-output-buffered-file)
 3257 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3263     # check output
 3264     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 3265     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 3266     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 3267     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 3268     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 3269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 3270     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 3271     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 3272     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 3273     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 3274     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 3275     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 3276     (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")
 3277     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 3278     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 3279     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 3280     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 3281     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 3282     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 3283     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 3284     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 3285     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 3286     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 3287     # . epilogue
 3288     89/<- %esp 5/r32/ebp
 3289     5d/pop-to-ebp
 3290     c3/return
 3291 
 3292 test-convert-function-with-multiple-vars-in-nested-blocks:
 3293     # . prologue
 3294     55/push-ebp
 3295     89/<- %ebp 4/r32/esp
 3296     # setup
 3297     (clear-stream _test-input-stream)
 3298     (clear-stream $_test-input-buffered-file->buffer)
 3299     (clear-stream _test-output-stream)
 3300     (clear-stream $_test-output-buffered-file->buffer)
 3301     #
 3302     (write _test-input-stream "fn foo x: int {\n")
 3303     (write _test-input-stream "  {\n")
 3304     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 3305     (write _test-input-stream "    {\n")
 3306     (write _test-input-stream "      var y: int\n")
 3307     (write _test-input-stream "      x <- add y\n")
 3308     (write _test-input-stream "    }\n")
 3309     (write _test-input-stream "  }\n")
 3310     (write _test-input-stream "}\n")
 3311     # convert
 3312     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3313     (flush _test-output-buffered-file)
 3314 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3320     # check output
 3321     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 3322     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 3323     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 3324     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 3325     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 3326     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 3327     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 3328     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 3329     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 3330     (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")
 3331     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 3332     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 3333     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 3334     (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")
 3335     (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")
 3336     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 3337     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 3338     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 3339     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 3340     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 3341     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 3342     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 3343     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 3344     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 3345     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 3346     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 3347     # . epilogue
 3348     89/<- %esp 5/r32/ebp
 3349     5d/pop-to-ebp
 3350     c3/return
 3351 
 3352 test-convert-function-with-branches-and-local-vars:
 3353     # A conditional 'break' after a 'var' in a block is converted into a
 3354     # nested block that performs all necessary cleanup before jumping. This
 3355     # results in some ugly code duplication.
 3356     # . prologue
 3357     55/push-ebp
 3358     89/<- %ebp 4/r32/esp
 3359     # setup
 3360     (clear-stream _test-input-stream)
 3361     (clear-stream $_test-input-buffered-file->buffer)
 3362     (clear-stream _test-output-stream)
 3363     (clear-stream $_test-output-buffered-file->buffer)
 3364     #
 3365     (write _test-input-stream "fn foo {\n")
 3366     (write _test-input-stream "  {\n")
 3367     (write _test-input-stream "    var x: int\n")
 3368     (write _test-input-stream "    break-if->=\n")
 3369     (write _test-input-stream "    increment x\n")
 3370     (write _test-input-stream "  }\n")
 3371     (write _test-input-stream "}\n")
 3372     # convert
 3373     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3374     (flush _test-output-buffered-file)
 3375 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3381     # check output
 3382     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 3383     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 3384     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 3385     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 3386     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 3387     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 3388     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 3389     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 3390     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 3391     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 3392     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 3393     (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")
 3394     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 3395     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 3396     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 3397     (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")
 3398     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 3399     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 3400     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 3401     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 3402     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 3403     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 3404     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 3405     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 3406     # . epilogue
 3407     89/<- %esp 5/r32/ebp
 3408     5d/pop-to-ebp
 3409     c3/return
 3410 
 3411 test-convert-function-with-conditional-loops-and-local-vars:
 3412     # A conditional 'loop' after a 'var' in a block is converted into a nested
 3413     # block that performs all necessary cleanup before jumping. This results
 3414     # in some ugly code duplication.
 3415     # . prologue
 3416     55/push-ebp
 3417     89/<- %ebp 4/r32/esp
 3418     # setup
 3419     (clear-stream _test-input-stream)
 3420     (clear-stream $_test-input-buffered-file->buffer)
 3421     (clear-stream _test-output-stream)
 3422     (clear-stream $_test-output-buffered-file->buffer)
 3423     #
 3424     (write _test-input-stream "fn foo {\n")
 3425     (write _test-input-stream "  {\n")
 3426     (write _test-input-stream "    var x: int\n")
 3427     (write _test-input-stream "    loop-if->=\n")
 3428     (write _test-input-stream "    increment x\n")
 3429     (write _test-input-stream "  }\n")
 3430     (write _test-input-stream "}\n")
 3431     # convert
 3432     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3433     (flush _test-output-buffered-file)
 3434 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3440     # check output
 3441     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 3442     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 3443     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 3444     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 3445     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 3446     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 3447     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 3448     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 3449     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 3450     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 3451     (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")
 3452     (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")
 3453     (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")
 3454     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 3455     (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")
 3456     (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")
 3457     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 3458     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 3459     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 3460     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 3461     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 3462     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 3463     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 3464     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 3465     # . epilogue
 3466     89/<- %esp 5/r32/ebp
 3467     5d/pop-to-ebp
 3468     c3/return
 3469 
 3470 test-convert-function-with-unconditional-loops-and-local-vars:
 3471     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 3472     # regular block cleanup. Any instructions after 'loop' are dead and
 3473     # therefore skipped.
 3474     # . prologue
 3475     55/push-ebp
 3476     89/<- %ebp 4/r32/esp
 3477     # setup
 3478     (clear-stream _test-input-stream)
 3479     (clear-stream $_test-input-buffered-file->buffer)
 3480     (clear-stream _test-output-stream)
 3481     (clear-stream $_test-output-buffered-file->buffer)
 3482     #
 3483     (write _test-input-stream "fn foo {\n")
 3484     (write _test-input-stream "  {\n")
 3485     (write _test-input-stream "    var x: int\n")
 3486     (write _test-input-stream "    loop\n")
 3487     (write _test-input-stream "    increment x\n")
 3488     (write _test-input-stream "  }\n")
 3489     (write _test-input-stream "}\n")
 3490     # convert
 3491     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3492     (flush _test-output-buffered-file)
 3493 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3499     # check output
 3500     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 3501     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 3502     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 3503     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 3504     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 3505     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 3506     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 3507     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 3508     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 3509     (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")
 3510     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 3511     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 3512     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 3513     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 3514     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 3515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 3516     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 3517     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 3518     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 3519     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 3520     # . epilogue
 3521     89/<- %esp 5/r32/ebp
 3522     5d/pop-to-ebp
 3523     c3/return
 3524 
 3525 test-convert-function-with-branches-and-loops-and-local-vars:
 3526     # . prologue
 3527     55/push-ebp
 3528     89/<- %ebp 4/r32/esp
 3529     # setup
 3530     (clear-stream _test-input-stream)
 3531     (clear-stream $_test-input-buffered-file->buffer)
 3532     (clear-stream _test-output-stream)
 3533     (clear-stream $_test-output-buffered-file->buffer)
 3534     #
 3535     (write _test-input-stream "fn foo {\n")
 3536     (write _test-input-stream "  {\n")
 3537     (write _test-input-stream "    var x: int\n")
 3538     (write _test-input-stream "    break-if->=\n")
 3539     (write _test-input-stream "    increment x\n")
 3540     (write _test-input-stream "    loop\n")
 3541     (write _test-input-stream "  }\n")
 3542     (write _test-input-stream "}\n")
 3543     # convert
 3544     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3545     (flush _test-output-buffered-file)
 3546 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3552     # check output
 3553     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3554     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3555     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3556     (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")
 3557     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3558     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3559     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3560     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3561     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3562     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3563     (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")
 3564     (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")
 3565     (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")
 3566     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3567     (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")
 3568     (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")
 3569     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3570     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3571     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3572     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3573     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3574     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3575     (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")
 3576     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3577     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3578     # . epilogue
 3579     89/<- %esp 5/r32/ebp
 3580     5d/pop-to-ebp
 3581     c3/return
 3582 
 3583 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3584     # . prologue
 3585     55/push-ebp
 3586     89/<- %ebp 4/r32/esp
 3587     # setup
 3588     (clear-stream _test-input-stream)
 3589     (clear-stream $_test-input-buffered-file->buffer)
 3590     (clear-stream _test-output-stream)
 3591     (clear-stream $_test-output-buffered-file->buffer)
 3592     #
 3593     (write _test-input-stream "fn foo {\n")
 3594     (write _test-input-stream "  a: {\n")
 3595     (write _test-input-stream "    var x: int\n")
 3596     (write _test-input-stream "    {\n")
 3597     (write _test-input-stream "      var y: int\n")
 3598     (write _test-input-stream "      break-if->= a\n")
 3599     (write _test-input-stream "      increment x\n")
 3600     (write _test-input-stream "      loop\n")
 3601     (write _test-input-stream "    }\n")
 3602     (write _test-input-stream "  }\n")
 3603     (write _test-input-stream "}\n")
 3604     # convert
 3605     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3606     (flush _test-output-buffered-file)
 3607 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3613     # check output
 3614     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3615     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3616     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3617     (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")
 3618     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3619     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3620     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3621     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3622     (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")
 3623     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3624     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3625     (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")
 3626     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3627     (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")
 3628     (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")
 3629     (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")
 3630     (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")
 3631     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3632     (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")
 3633     (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")
 3634     (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")
 3635     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3636     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3637     (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")
 3638     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3639     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3640     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3641     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3642     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3643     (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")
 3644     (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")
 3645     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3646     # . epilogue
 3647     89/<- %esp 5/r32/ebp
 3648     5d/pop-to-ebp
 3649     c3/return
 3650 
 3651 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3652     # . prologue
 3653     55/push-ebp
 3654     89/<- %ebp 4/r32/esp
 3655     # setup
 3656     (clear-stream _test-input-stream)
 3657     (clear-stream $_test-input-buffered-file->buffer)
 3658     (clear-stream _test-output-stream)
 3659     (clear-stream $_test-output-buffered-file->buffer)
 3660     # non-local conditional branch from a block without a local variable,
 3661     # unwinding a local on the stack
 3662     (write _test-input-stream "fn foo {\n")
 3663     (write _test-input-stream "  a: {\n")
 3664     (write _test-input-stream "    var x: int\n")
 3665     (write _test-input-stream "    {\n")
 3666     (write _test-input-stream "      break-if->= a\n")
 3667     (write _test-input-stream "    }\n")
 3668     (write _test-input-stream "  }\n")
 3669     (write _test-input-stream "}\n")
 3670     # convert
 3671     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3672     (flush _test-output-buffered-file)
 3673 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3679     # check output
 3680     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3681     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3682     (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")
 3683     (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")
 3684     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3685     (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")
 3686     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3687     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3688     (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")
 3689     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3690     (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")
 3691     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3692     (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")
 3693     (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")
 3694     (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")
 3695     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3696     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3697     (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")
 3698     (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")
 3699     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3700     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3701     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3702     (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")
 3703     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3704     (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")
 3705     (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")
 3706     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3707     # . epilogue
 3708     89/<- %esp 5/r32/ebp
 3709     5d/pop-to-ebp
 3710     c3/return
 3711 
 3712 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3713     # . prologue
 3714     55/push-ebp
 3715     89/<- %ebp 4/r32/esp
 3716     # setup
 3717     (clear-stream _test-input-stream)
 3718     (clear-stream $_test-input-buffered-file->buffer)
 3719     (clear-stream _test-output-stream)
 3720     (clear-stream $_test-output-buffered-file->buffer)
 3721     # non-local unconditional branch from a block without a local variable,
 3722     # unwinding a local on the stack
 3723     (write _test-input-stream "fn foo {\n")
 3724     (write _test-input-stream "  a: {\n")
 3725     (write _test-input-stream "    var x: int\n")
 3726     (write _test-input-stream "    {\n")
 3727     (write _test-input-stream "      break a\n")
 3728     (write _test-input-stream "    }\n")
 3729     (write _test-input-stream "  }\n")
 3730     (write _test-input-stream "}\n")
 3731     # convert
 3732     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3733     (flush _test-output-buffered-file)
 3734 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3740     # check output
 3741     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3742     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3743     (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")
 3744     (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")
 3745     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3746     (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")
 3747     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3748     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3749     (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")
 3750     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3751     (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")
 3752     (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")
 3753     (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")
 3754     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3755     (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")
 3756     (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")
 3757     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3758     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3759     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3760     (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")
 3761     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3762     (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")
 3763     (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")
 3764     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3765     # . epilogue
 3766     89/<- %esp 5/r32/ebp
 3767     5d/pop-to-ebp
 3768     c3/return
 3769 
 3770 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3771     # . prologue
 3772     55/push-ebp
 3773     89/<- %ebp 4/r32/esp
 3774     # setup
 3775     (clear-stream _test-input-stream)
 3776     (clear-stream $_test-input-buffered-file->buffer)
 3777     (clear-stream _test-output-stream)
 3778     (clear-stream $_test-output-buffered-file->buffer)
 3779     #
 3780     (write _test-input-stream "fn foo {\n")
 3781     (write _test-input-stream "  a: {\n")
 3782     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3783     (write _test-input-stream "    {\n")
 3784     (write _test-input-stream "      break a\n")
 3785     (write _test-input-stream "    }\n")
 3786     (write _test-input-stream "  }\n")
 3787     (write _test-input-stream "}\n")
 3788     # convert
 3789     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3790     (flush _test-output-buffered-file)
 3791 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3797     # check output
 3798     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3799     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3800     (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")
 3801     (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")
 3802     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3803     (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")
 3804     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3805     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3806     (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")
 3807     (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")
 3808     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3809     (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")
 3810     (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")
 3811     (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")
 3812     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3813     (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")
 3814     (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")
 3815     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3816     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3817     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3818     (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")
 3819     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3820     (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")
 3821     (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")
 3822     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3823     # . epilogue
 3824     89/<- %esp 5/r32/ebp
 3825     5d/pop-to-ebp
 3826     c3/return
 3827 
 3828 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3829     # . prologue
 3830     55/push-ebp
 3831     89/<- %ebp 4/r32/esp
 3832     # setup
 3833     (clear-stream _test-input-stream)
 3834     (clear-stream $_test-input-buffered-file->buffer)
 3835     (clear-stream _test-output-stream)
 3836     (clear-stream $_test-output-buffered-file->buffer)
 3837     #
 3838     (write _test-input-stream "fn foo {\n")
 3839     (write _test-input-stream "  a: {\n")
 3840     (write _test-input-stream "    var x: int\n")
 3841     (write _test-input-stream "    {\n")
 3842     (write _test-input-stream "      var y: int\n")
 3843     (write _test-input-stream "      break a\n")
 3844     (write _test-input-stream "      increment x\n")
 3845     (write _test-input-stream "    }\n")
 3846     (write _test-input-stream "  }\n")
 3847     (write _test-input-stream "}\n")
 3848     # convert
 3849     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3850     (flush _test-output-buffered-file)
 3851 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3857     # check output
 3858     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3859     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3860     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3861     (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")
 3862     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3863     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3864     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3865     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3866     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3867     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3868     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3869     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3870     (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")
 3871     (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")
 3872     (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")
 3873     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3874     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3875     (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")
 3876     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3877     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3878     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3880     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3881     (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")
 3882     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3883     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3884     # . epilogue
 3885     89/<- %esp 5/r32/ebp
 3886     5d/pop-to-ebp
 3887     c3/return
 3888 
 3889 test-convert-function-with-unconditional-break-and-local-vars:
 3890     # . prologue
 3891     55/push-ebp
 3892     89/<- %ebp 4/r32/esp
 3893     # setup
 3894     (clear-stream _test-input-stream)
 3895     (clear-stream $_test-input-buffered-file->buffer)
 3896     (clear-stream _test-output-stream)
 3897     (clear-stream $_test-output-buffered-file->buffer)
 3898     #
 3899     (write _test-input-stream "fn foo {\n")
 3900     (write _test-input-stream "  {\n")
 3901     (write _test-input-stream "    var x: int\n")
 3902     (write _test-input-stream "    {\n")
 3903     (write _test-input-stream "      var y: int\n")
 3904     (write _test-input-stream "      break\n")
 3905     (write _test-input-stream "      increment x\n")
 3906     (write _test-input-stream "    }\n")
 3907     (write _test-input-stream "  }\n")
 3908     (write _test-input-stream "}\n")
 3909     # convert
 3910     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3911     (flush _test-output-buffered-file)
 3912 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3918     # check output
 3919     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3920     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3921     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3922     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3923     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3924     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3925     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3926     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3927     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3928     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3930     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3931     (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")
 3932     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3933     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3934     (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")
 3935     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3936     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3937     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3938     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3939     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3940     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3941     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3942     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3943     # . epilogue
 3944     89/<- %esp 5/r32/ebp
 3945     5d/pop-to-ebp
 3946     c3/return
 3947 
 3948 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3949     # . prologue
 3950     55/push-ebp
 3951     89/<- %ebp 4/r32/esp
 3952     # setup
 3953     (clear-stream _test-input-stream)
 3954     (clear-stream $_test-input-buffered-file->buffer)
 3955     (clear-stream _test-output-stream)
 3956     (clear-stream $_test-output-buffered-file->buffer)
 3957     #
 3958     (write _test-input-stream "fn foo {\n")
 3959     (write _test-input-stream "  a: {\n")
 3960     (write _test-input-stream "    var x: int\n")
 3961     (write _test-input-stream "    {\n")
 3962     (write _test-input-stream "      var y: int\n")
 3963     (write _test-input-stream "      loop a\n")
 3964     (write _test-input-stream "      increment x\n")
 3965     (write _test-input-stream "    }\n")
 3966     (write _test-input-stream "  }\n")
 3967     (write _test-input-stream "}\n")
 3968     # convert
 3969     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3970     (flush _test-output-buffered-file)
 3971 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3977     # check output
 3978     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3979     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3980     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3981     (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")
 3982     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3983     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3984     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3985     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3986     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3987     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3988     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3989     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3990     (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")
 3991     (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")
 3992     (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")
 3993     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3994     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3995     (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")
 3996     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3997     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3998     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3999     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 4000     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 4001     (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")
 4002     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 4003     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 4004     # . epilogue
 4005     89/<- %esp 5/r32/ebp
 4006     5d/pop-to-ebp
 4007     c3/return
 4008 
 4009 test-convert-function-with-local-array-var-in-mem:
 4010     # . prologue
 4011     55/push-ebp
 4012     89/<- %ebp 4/r32/esp
 4013     # setup
 4014     (clear-stream _test-input-stream)
 4015     (clear-stream $_test-input-buffered-file->buffer)
 4016     (clear-stream _test-output-stream)
 4017     (clear-stream $_test-output-buffered-file->buffer)
 4018     #
 4019     (write _test-input-stream "fn foo {\n")
 4020     (write _test-input-stream "  var x: (array int 3)\n")
 4021     (write _test-input-stream "}\n")
 4022     # convert
 4023     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4024     (flush _test-output-buffered-file)
 4025 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4031     # check output
 4032     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 4033     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 4034     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 4035     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 4036     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 4037     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 4038     # define x
 4039     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 4040     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 4041     # reclaim x
 4042     (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")
 4043     #
 4044     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 4045     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 4046     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 4047     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 4048     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 4049     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 4050     # . epilogue
 4051     89/<- %esp 5/r32/ebp
 4052     5d/pop-to-ebp
 4053     c3/return
 4054 
 4055 test-array-size-in-hex:
 4056     # . prologue
 4057     55/push-ebp
 4058     89/<- %ebp 4/r32/esp
 4059     # setup
 4060     (clear-stream _test-input-stream)
 4061     (clear-stream $_test-input-buffered-file->buffer)
 4062     (clear-stream _test-output-stream)
 4063     (clear-stream $_test-output-buffered-file->buffer)
 4064     (clear-stream _test-error-stream)
 4065     (clear-stream $_test-error-buffered-file->buffer)
 4066     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4067     68/push 0/imm32
 4068     68/push 0/imm32
 4069     89/<- %edx 4/r32/esp
 4070     (tailor-exit-descriptor %edx 0x10)
 4071     #
 4072     (write _test-input-stream "fn foo {\n")
 4073     (write _test-input-stream "  var x: (array int 10)\n")
 4074     (write _test-input-stream "}\n")
 4075     # convert
 4076     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4077     # registers except esp clobbered at this point
 4078     # restore ed
 4079     89/<- %edx 4/r32/esp
 4080     (flush _test-output-buffered-file)
 4081     (flush _test-error-buffered-file)
 4082 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4088     # check output
 4089     (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
 4090     (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")
 4091     # check that stop(1) was called
 4092     (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
 4093     # don't restore from ebp
 4094     81 0/subop/add %esp 8/imm32
 4095     # . epilogue
 4096     5d/pop-to-ebp
 4097     c3/return
 4098 
 4099 test-convert-function-with-populate:
 4100     # . prologue
 4101     55/push-ebp
 4102     89/<- %ebp 4/r32/esp
 4103     # setup
 4104     (clear-stream _test-input-stream)
 4105     (clear-stream $_test-input-buffered-file->buffer)
 4106     (clear-stream _test-output-stream)
 4107     (clear-stream $_test-output-buffered-file->buffer)
 4108     #
 4109     (write _test-input-stream "fn foo {\n")
 4110     (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
 4111     (write _test-input-stream "  populate x, 7\n")
 4112     (write _test-input-stream "}\n")
 4113     # convert
 4114     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4115     (flush _test-output-buffered-file)
 4116 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4122     # check output
 4123     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
 4124     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
 4125     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
 4126     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
 4127     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
 4128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
 4129     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
 4130     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
 4131     (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)
 4132     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
 4133     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
 4134     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
 4135     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
 4136     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
 4137     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
 4138     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
 4139     # . epilogue
 4140     89/<- %esp 5/r32/ebp
 4141     5d/pop-to-ebp
 4142     c3/return
 4143 
 4144 # special-case for size(byte) when allocating array
 4145 test-convert-function-with-local-array-of-bytes-in-mem:
 4146     # . prologue
 4147     55/push-ebp
 4148     89/<- %ebp 4/r32/esp
 4149     # setup
 4150     (clear-stream _test-input-stream)
 4151     (clear-stream $_test-input-buffered-file->buffer)
 4152     (clear-stream _test-output-stream)
 4153     (clear-stream $_test-output-buffered-file->buffer)
 4154     #
 4155     (write _test-input-stream "fn foo {\n")
 4156     (write _test-input-stream "  var x: (array byte 3)\n")
 4157     (write _test-input-stream "}\n")
 4158     # convert
 4159     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4160     (flush _test-output-buffered-file)
 4161 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4167     # check output
 4168     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 4169     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 4170     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 4171     (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")
 4172     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 4173     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 4174     # define x
 4175     (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")
 4176     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 4177     # reclaim x
 4178     (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")
 4179     #
 4180     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 4181     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 4182     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 4183     (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")
 4184     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 4185     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 4186     # . epilogue
 4187     89/<- %esp 5/r32/ebp
 4188     5d/pop-to-ebp
 4189     c3/return
 4190 
 4191 test-convert-address:
 4192     # . prologue
 4193     55/push-ebp
 4194     89/<- %ebp 4/r32/esp
 4195     # setup
 4196     (clear-stream _test-input-stream)
 4197     (clear-stream $_test-input-buffered-file->buffer)
 4198     (clear-stream _test-output-stream)
 4199     (clear-stream $_test-output-buffered-file->buffer)
 4200     #
 4201     (write _test-input-stream "fn foo {\n")
 4202     (write _test-input-stream "  var a: int\n")
 4203     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 4204     (write _test-input-stream "}\n")
 4205     # convert
 4206     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4207     (flush _test-output-buffered-file)
 4208 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4214     # check output
 4215     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 4216     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 4217     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 4218     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 4219     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 4220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 4221     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 4222     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 4223     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 4224     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 4225     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 4226     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 4227     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 4228     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 4229     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 4230     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 4231     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 4232     # . epilogue
 4233     89/<- %esp 5/r32/ebp
 4234     5d/pop-to-ebp
 4235     c3/return
 4236 
 4237 test-convert-length-of-array:
 4238     # . prologue
 4239     55/push-ebp
 4240     89/<- %ebp 4/r32/esp
 4241     # setup
 4242     (clear-stream _test-input-stream)
 4243     (clear-stream $_test-input-buffered-file->buffer)
 4244     (clear-stream _test-output-stream)
 4245     (clear-stream $_test-output-buffered-file->buffer)
 4246     #
 4247     (write _test-input-stream "fn foo a: (addr array int) {\n")
 4248     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 4249     (write _test-input-stream "  var c/eax: int <- length b\n")
 4250     (write _test-input-stream "}\n")
 4251     # convert
 4252     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4253     (flush _test-output-buffered-file)
 4254 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4260     # check output
 4261     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 4262     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 4263     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 4264     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 4265     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 4266     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 4267     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 4268     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 4269     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 4270     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 4271     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 4272     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 4273     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 4274     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 4275     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 4276     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 4277     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 4278     # . epilogue
 4279     89/<- %esp 5/r32/ebp
 4280     5d/pop-to-ebp
 4281     c3/return
 4282 
 4283 # special-case for size(byte) when computing array length
 4284 test-convert-length-of-array-of-bytes:
 4285     # . prologue
 4286     55/push-ebp
 4287     89/<- %ebp 4/r32/esp
 4288     # setup
 4289     (clear-stream _test-input-stream)
 4290     (clear-stream $_test-input-buffered-file->buffer)
 4291     (clear-stream _test-output-stream)
 4292     (clear-stream $_test-output-buffered-file->buffer)
 4293     #
 4294     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 4295     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 4296     (write _test-input-stream "  var c/eax: int <- length b\n")
 4297     (write _test-input-stream "}\n")
 4298     # convert
 4299     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4300     (flush _test-output-buffered-file)
 4301 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4307     # check output
 4308     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 4309     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 4310     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 4311     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 4312     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 4313     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 4314     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 4315     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 4316     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 4317     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 4318     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 4319     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 4320     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 4321     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 4322     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 4323     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 4324     # . epilogue
 4325     89/<- %esp 5/r32/ebp
 4326     5d/pop-to-ebp
 4327     c3/return
 4328 
 4329 test-convert-length-of-array-on-stack:
 4330     # . prologue
 4331     55/push-ebp
 4332     89/<- %ebp 4/r32/esp
 4333     # setup
 4334     (clear-stream _test-input-stream)
 4335     (clear-stream $_test-input-buffered-file->buffer)
 4336     (clear-stream _test-output-stream)
 4337     (clear-stream $_test-output-buffered-file->buffer)
 4338     #
 4339     (write _test-input-stream "fn foo {\n")
 4340     (write _test-input-stream "  var a: (array int 3)\n")
 4341     (write _test-input-stream "  var b/eax: int <- length a\n")
 4342     (write _test-input-stream "}\n")
 4343     # convert
 4344     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4345     (flush _test-output-buffered-file)
 4346 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4352     # check output
 4353     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 4354     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 4355     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 4356     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 4357     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 4358     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 4359     # define x
 4360     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 4361     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 4362     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 4363     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 4364     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 4365     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 4366     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 4367     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 4368     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 4369     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 4370     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 4371     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 4372     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 4373     # . epilogue
 4374     89/<- %esp 5/r32/ebp
 4375     5d/pop-to-ebp
 4376     c3/return
 4377 
 4378 test-reg-var-def-with-read-of-same-register:
 4379     # . prologue
 4380     55/push-ebp
 4381     89/<- %ebp 4/r32/esp
 4382     # setup
 4383     (clear-stream _test-input-stream)
 4384     (clear-stream $_test-input-buffered-file->buffer)
 4385     (clear-stream _test-output-stream)
 4386     (clear-stream $_test-output-buffered-file->buffer)
 4387     (clear-stream _test-error-stream)
 4388     (clear-stream $_test-error-buffered-file->buffer)
 4389     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 4390     68/push 0/imm32
 4391     68/push 0/imm32
 4392     89/<- %edx 4/r32/esp
 4393     (tailor-exit-descriptor %edx 0x10)
 4394     #
 4395     (write _test-input-stream "fn foo {\n")
 4396     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4397     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4398     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4399     (write _test-input-stream "}\n")
 4400     # convert
 4401     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4402     # registers except esp could be clobbered at this point (though they shouldn't be)
 4403     # restore ed
 4404     89/<- %edx 4/r32/esp
 4405     (flush _test-output-buffered-file)
 4406     (flush _test-error-buffered-file)
 4407 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4413 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4419     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 4420     # check output
 4421     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 4422     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 4423     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 4424     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 4425     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 4426     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 4427     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 4428     (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")
 4429     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 4430     (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")
 4431     (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")
 4432     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 4433     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 4434     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 4435     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 4436     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 4437     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 4438     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 4439     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 4440     # don't restore from ebp
 4441     81 0/subop/add %esp 8/imm32
 4442     # . epilogue
 4443     5d/pop-to-ebp
 4444     c3/return
 4445 
 4446 test-convert-index-into-array:
 4447     # . prologue
 4448     55/push-ebp
 4449     89/<- %ebp 4/r32/esp
 4450     # setup
 4451     (clear-stream _test-input-stream)
 4452     (clear-stream $_test-input-buffered-file->buffer)
 4453     (clear-stream _test-output-stream)
 4454     (clear-stream $_test-output-buffered-file->buffer)
 4455     #
 4456     (write _test-input-stream "fn foo {\n")
 4457     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4458     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4459     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4460     (write _test-input-stream "}\n")
 4461     # convert
 4462     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4463     (flush _test-output-buffered-file)
 4464 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4470     # check output
 4471     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 4472     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 4473     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 4474     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 4475     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 4476     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 4477     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 4478     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 4479     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 4480     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 4481     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 4482     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 4483     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 4484     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 4485     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 4486     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 4487     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 4488     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 4489     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 4490     # . epilogue
 4491     89/<- %esp 5/r32/ebp
 4492     5d/pop-to-ebp
 4493     c3/return
 4494 
 4495 test-convert-index-into-array-of-bytes:
 4496     # . prologue
 4497     55/push-ebp
 4498     89/<- %ebp 4/r32/esp
 4499     # setup
 4500     (clear-stream _test-input-stream)
 4501     (clear-stream $_test-input-buffered-file->buffer)
 4502     (clear-stream _test-output-stream)
 4503     (clear-stream $_test-output-buffered-file->buffer)
 4504     #
 4505     (write _test-input-stream "fn foo {\n")
 4506     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4507     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4508     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 4509     (write _test-input-stream "}\n")
 4510     # convert
 4511     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4512     (flush _test-output-buffered-file)
 4513 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4519     # check output
 4520     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 4521     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 4522     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 4523     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 4524     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 4525     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 4526     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 4527     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 4528     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 4529     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 4530     (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")
 4531     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 4532     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 4533     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 4534     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 4535     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 4536     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 4537     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 4538     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 4539     # . epilogue
 4540     89/<- %esp 5/r32/ebp
 4541     5d/pop-to-ebp
 4542     c3/return
 4543 
 4544 test-convert-index-into-array-with-literal:
 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 {\n")
 4555     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4556     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\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-index-into-array-with-literal/0")
 4569     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 4570     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 4571     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 4572     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 4573     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 4574     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 4575     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 4576                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 4577     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 4578     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 4579     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 4580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 4581     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 4582     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 4583     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 4584     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 4585     # . epilogue
 4586     89/<- %esp 5/r32/ebp
 4587     5d/pop-to-ebp
 4588     c3/return
 4589 
 4590 test-convert-index-into-array-of-bytes-with-literal:
 4591     # . prologue
 4592     55/push-ebp
 4593     89/<- %ebp 4/r32/esp
 4594     # setup
 4595     (clear-stream _test-input-stream)
 4596     (clear-stream $_test-input-buffered-file->buffer)
 4597     (clear-stream _test-output-stream)
 4598     (clear-stream $_test-output-buffered-file->buffer)
 4599     #
 4600     (write _test-input-stream "fn foo {\n")
 4601     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4602     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4603     (write _test-input-stream "}\n")
 4604     # convert
 4605     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4606     (flush _test-output-buffered-file)
 4607 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4613     # check output
 4614     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 4615     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 4616     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 4617     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 4618     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 4619     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 4620     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 4621     (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")
 4622                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 4623     (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")
 4624     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 4625     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 4626     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4627     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4628     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4629     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4630     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4631     # . epilogue
 4632     89/<- %esp 5/r32/ebp
 4633     5d/pop-to-ebp
 4634     c3/return
 4635 
 4636 test-convert-index-into-array-on-stack:
 4637     # . prologue
 4638     55/push-ebp
 4639     89/<- %ebp 4/r32/esp
 4640     # setup
 4641     (clear-stream _test-input-stream)
 4642     (clear-stream $_test-input-buffered-file->buffer)
 4643     (clear-stream _test-output-stream)
 4644     (clear-stream $_test-output-buffered-file->buffer)
 4645     #
 4646     (write _test-input-stream "fn foo {\n")
 4647     (write _test-input-stream "  var arr: (array int 3)\n")
 4648     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4649     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4650     (write _test-input-stream "}\n")
 4651     # convert
 4652     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4653     (flush _test-output-buffered-file)
 4654 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4660     # check output
 4661     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4662     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4663     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4664     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4665     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4666     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4667     # var arr
 4668     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4669     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4670     # var idx
 4671     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4672     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4673     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4674     (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")
 4675     # reclaim idx
 4676     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4677     # reclaim arr
 4678     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4679     #
 4680     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4682     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4683     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4684     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4685     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4686     # . epilogue
 4687     89/<- %esp 5/r32/ebp
 4688     5d/pop-to-ebp
 4689     c3/return
 4690 
 4691 test-convert-index-into-array-on-stack-with-literal:
 4692     # . prologue
 4693     55/push-ebp
 4694     89/<- %ebp 4/r32/esp
 4695     # setup
 4696     (clear-stream _test-input-stream)
 4697     (clear-stream $_test-input-buffered-file->buffer)
 4698     (clear-stream _test-output-stream)
 4699     (clear-stream $_test-output-buffered-file->buffer)
 4700     #
 4701     (write _test-input-stream "fn foo {\n")
 4702     (write _test-input-stream "  var arr: (array int 3)\n")
 4703     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4704     (write _test-input-stream "}\n")
 4705     # convert
 4706     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4707     (flush _test-output-buffered-file)
 4708 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4714     # check output
 4715     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4716     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4717     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4718     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4719     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4720     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4721     # var arr
 4722     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4723     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4724     # var x
 4725     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4726     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4727     (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")
 4728     # reclaim x
 4729     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4730     # reclaim arr
 4731     (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")
 4732     #
 4733     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4735     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4736     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4737     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4738     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4739     # . epilogue
 4740     89/<- %esp 5/r32/ebp
 4741     5d/pop-to-ebp
 4742     c3/return
 4743 
 4744 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4745     # . prologue
 4746     55/push-ebp
 4747     89/<- %ebp 4/r32/esp
 4748     # setup
 4749     (clear-stream _test-input-stream)
 4750     (clear-stream $_test-input-buffered-file->buffer)
 4751     (clear-stream _test-output-stream)
 4752     (clear-stream $_test-output-buffered-file->buffer)
 4753     #
 4754     (write _test-input-stream "fn foo {\n")
 4755     (write _test-input-stream "  var arr: (array byte 3)\n")
 4756     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4757     (write _test-input-stream "}\n")
 4758     # convert
 4759     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4760     (flush _test-output-buffered-file)
 4761 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4767     # check output
 4768     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4769     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4770     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4771     (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")
 4772     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4773     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4774     # var arr
 4775     (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")
 4776     (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")
 4777     # var x
 4778     (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")
 4779     # x is at (ebp-7) + 4 + 2 = ebp-1
 4780     (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")
 4781     # reclaim x
 4782     (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")
 4783     # reclaim arr
 4784     (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")
 4785     #
 4786     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4787     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4788     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4789     (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")
 4790     (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")
 4791     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4792     # . epilogue
 4793     89/<- %esp 5/r32/ebp
 4794     5d/pop-to-ebp
 4795     c3/return
 4796 
 4797 test-convert-index-into-array-using-offset:
 4798     # . prologue
 4799     55/push-ebp
 4800     89/<- %ebp 4/r32/esp
 4801     # setup
 4802     (clear-stream _test-input-stream)
 4803     (clear-stream $_test-input-buffered-file->buffer)
 4804     (clear-stream _test-output-stream)
 4805     (clear-stream $_test-output-buffered-file->buffer)
 4806     #
 4807     (write _test-input-stream "fn foo {\n")
 4808     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4809     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4810     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4811     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4812     (write _test-input-stream "}\n")
 4813     # convert
 4814     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4815     (flush _test-output-buffered-file)
 4816 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4822     # check output
 4823     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4824     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4825     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4826     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4827     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4828     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4829     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4830     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4831     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4832     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4833     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4834     (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")
 4835     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4836     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4837     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4838     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4839     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4840     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4841     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4842     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4843     # . epilogue
 4844     89/<- %esp 5/r32/ebp
 4845     5d/pop-to-ebp
 4846     c3/return
 4847 
 4848 test-convert-index-into-array-of-bytes-using-offset:
 4849     # . prologue
 4850     55/push-ebp
 4851     89/<- %ebp 4/r32/esp
 4852     # setup
 4853     (clear-stream _test-input-stream)
 4854     (clear-stream $_test-input-buffered-file->buffer)
 4855     (clear-stream _test-output-stream)
 4856     (clear-stream $_test-output-buffered-file->buffer)
 4857     #
 4858     (write _test-input-stream "fn foo {\n")
 4859     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4860     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4861     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4862     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\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-using-offset/0")
 4875     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4876     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4877     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4878     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4880     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4881     (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")
 4882     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4883     (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")
 4884     (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")
 4885     (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")
 4886     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4887     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4888     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4889     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4890     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4891     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4892     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4893     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4894     # . epilogue
 4895     89/<- %esp 5/r32/ebp
 4896     5d/pop-to-ebp
 4897     c3/return
 4898 
 4899 test-convert-index-into-array-using-offset-on-stack:
 4900     # . prologue
 4901     55/push-ebp
 4902     89/<- %ebp 4/r32/esp
 4903     # setup
 4904     (clear-stream _test-input-stream)
 4905     (clear-stream $_test-input-buffered-file->buffer)
 4906     (clear-stream _test-output-stream)
 4907     (clear-stream $_test-output-buffered-file->buffer)
 4908     #
 4909     (write _test-input-stream "fn foo {\n")
 4910     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4911     (write _test-input-stream "  var idx: int\n")
 4912     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4913     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4914     (write _test-input-stream "}\n")
 4915     # convert
 4916     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4917     (flush _test-output-buffered-file)
 4918 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4924     # check output
 4925     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4926     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4927     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4928     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4929     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4930     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4931     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4932     (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")
 4933     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4934     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4935     (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")
 4936     (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")
 4937     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4938     (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")
 4939     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4940     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4945     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4946     # . epilogue
 4947     89/<- %esp 5/r32/ebp
 4948     5d/pop-to-ebp
 4949     c3/return
 4950 
 4951 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 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/eax: (addr array byte) <- copy 0\n")
 4963     (write _test-input-stream "  var idx: int\n")
 4964     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4965     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4966     (write _test-input-stream "}\n")
 4967     # convert
 4968     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4969     (flush _test-output-buffered-file)
 4970 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 4976     # check output
 4977     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4978     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4979     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4980     (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")
 4981     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4982     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4983     (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")
 4984     (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")
 4985     (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")
 4986     (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")
 4987     (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")
 4988     (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")
 4989     (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")
 4990     (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")
 4991     (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")
 4992     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4993     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4994     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4995     (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")
 4996     (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")
 4997     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4998     # . epilogue
 4999     89/<- %esp 5/r32/ebp
 5000     5d/pop-to-ebp
 5001     c3/return
 5002 
 5003 test-convert-function-and-type-definition:
 5004     # . prologue
 5005     55/push-ebp
 5006     89/<- %ebp 4/r32/esp
 5007     # setup
 5008     (clear-stream _test-input-stream)
 5009     (clear-stream $_test-input-buffered-file->buffer)
 5010     (clear-stream _test-output-stream)
 5011     (clear-stream $_test-output-buffered-file->buffer)
 5012     #
 5013     (write _test-input-stream "fn foo a: (addr t) {\n")
 5014     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 5015     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 5016     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 5017     (write _test-input-stream "}\n")
 5018     (write _test-input-stream "type t {\n")
 5019     (write _test-input-stream "  x: int\n")
 5020     (write _test-input-stream "  y: int\n")
 5021     (write _test-input-stream "}\n")
 5022     # convert
 5023     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5024     (flush _test-output-buffered-file)
 5025 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5031     # check output
 5032     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 5033     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 5034     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 5035     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 5036     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 5037     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 5038     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 5039     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 5040     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 5041     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 5042     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 5043     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 5044     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 5045     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 5046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 5047     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 5048     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 5049     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 5050     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 5051     # . epilogue
 5052     89/<- %esp 5/r32/ebp
 5053     5d/pop-to-ebp
 5054     c3/return
 5055 
 5056 test-type-definition-with-array:
 5057     # . prologue
 5058     55/push-ebp
 5059     89/<- %ebp 4/r32/esp
 5060     # setup
 5061     (clear-stream _test-input-stream)
 5062     (clear-stream $_test-input-buffered-file->buffer)
 5063     (clear-stream _test-output-stream)
 5064     (clear-stream $_test-output-buffered-file->buffer)
 5065     (clear-stream _test-error-stream)
 5066     (clear-stream $_test-error-buffered-file->buffer)
 5067     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5068     68/push 0/imm32
 5069     68/push 0/imm32
 5070     89/<- %edx 4/r32/esp
 5071     (tailor-exit-descriptor %edx 0x10)
 5072     #
 5073     (write _test-input-stream "type t {\n")
 5074     (write _test-input-stream "  a: (array int 3)\n")
 5075     (write _test-input-stream "}\n")
 5076     # convert
 5077     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5078     # registers except esp clobbered at this point
 5079     # restore ed
 5080     89/<- %edx 4/r32/esp
 5081     (flush _test-output-buffered-file)
 5082     (flush _test-error-buffered-file)
 5083 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5089     # check output
 5090     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
 5091     (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
 5092     # check that stop(1) was called
 5093     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
 5094     # don't restore from ebp
 5095     81 0/subop/add %esp 8/imm32
 5096     # . epilogue
 5097     5d/pop-to-ebp
 5098     c3/return
 5099 
 5100 test-type-definition-with-addr:
 5101     # . prologue
 5102     55/push-ebp
 5103     89/<- %ebp 4/r32/esp
 5104     # setup
 5105     (clear-stream _test-input-stream)
 5106     (clear-stream $_test-input-buffered-file->buffer)
 5107     (clear-stream _test-output-stream)
 5108     (clear-stream $_test-output-buffered-file->buffer)
 5109     (clear-stream _test-error-stream)
 5110     (clear-stream $_test-error-buffered-file->buffer)
 5111     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5112     68/push 0/imm32
 5113     68/push 0/imm32
 5114     89/<- %edx 4/r32/esp
 5115     (tailor-exit-descriptor %edx 0x10)
 5116     #
 5117     (write _test-input-stream "type t {\n")
 5118     (write _test-input-stream "  a: (addr int)\n")
 5119     (write _test-input-stream "}\n")
 5120     # convert
 5121     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5122     # registers except esp clobbered at this point
 5123     # restore ed
 5124     89/<- %edx 4/r32/esp
 5125     (flush _test-output-buffered-file)
 5126     (flush _test-error-buffered-file)
 5127 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5133     # check output
 5134     (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
 5135     (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
 5136     # check that stop(1) was called
 5137     (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
 5138     # don't restore from ebp
 5139     81 0/subop/add %esp 8/imm32
 5140     # . epilogue
 5141     5d/pop-to-ebp
 5142     c3/return
 5143 
 5144 test-convert-function-with-local-var-with-user-defined-type:
 5145     # . prologue
 5146     55/push-ebp
 5147     89/<- %ebp 4/r32/esp
 5148     # setup
 5149     (clear-stream _test-input-stream)
 5150     (clear-stream $_test-input-buffered-file->buffer)
 5151     (clear-stream _test-output-stream)
 5152     (clear-stream $_test-output-buffered-file->buffer)
 5153     #
 5154     (write _test-input-stream "fn foo {\n")
 5155     (write _test-input-stream "  var a: t\n")
 5156     (write _test-input-stream "}\n")
 5157     (write _test-input-stream "type t {\n")
 5158     (write _test-input-stream "  x: int\n")
 5159     (write _test-input-stream "  y: int\n")
 5160     (write _test-input-stream "}\n")
 5161     # convert
 5162     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5163     (flush _test-output-buffered-file)
 5164 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5170     # check output
 5171     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 5172     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 5173     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 5174     (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")
 5175     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 5176     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 5177     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 5178     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 5179     (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")
 5180     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 5181     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 5182     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 5183     (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")
 5184     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 5185     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 5186     # . epilogue
 5187     89/<- %esp 5/r32/ebp
 5188     5d/pop-to-ebp
 5189     c3/return
 5190 
 5191 test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
 5192     # . prologue
 5193     55/push-ebp
 5194     89/<- %ebp 4/r32/esp
 5195     # setup
 5196     (clear-stream _test-input-stream)
 5197     (clear-stream $_test-input-buffered-file->buffer)
 5198     (clear-stream _test-output-stream)
 5199     (clear-stream $_test-output-buffered-file->buffer)
 5200     #
 5201     (write _test-input-stream "fn foo {\n")
 5202     (write _test-input-stream "  var a: t\n")
 5203     (write _test-input-stream "}\n")
 5204     (write _test-input-stream "type t {\n")
 5205     (write _test-input-stream "  x: s\n")
 5206     (write _test-input-stream "}\n")
 5207     (write _test-input-stream "type s {\n")
 5208     (write _test-input-stream "  z: int\n")
 5209     (write _test-input-stream "}\n")
 5210     # convert
 5211     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5212     (flush _test-output-buffered-file)
 5213 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5219     # check output
 5220     (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")
 5221     (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")
 5222     (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")
 5223     (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")
 5224     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
 5225     (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")
 5226     (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")
 5227     (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")
 5228     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
 5229     (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")
 5230     (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")
 5231     (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")
 5232     (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")
 5233     (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")
 5234     # . epilogue
 5235     89/<- %esp 5/r32/ebp
 5236     5d/pop-to-ebp
 5237     c3/return
 5238 
 5239 test-convert-function-call-with-arg-of-user-defined-type:
 5240     # . prologue
 5241     55/push-ebp
 5242     89/<- %ebp 4/r32/esp
 5243     # setup
 5244     (clear-stream _test-input-stream)
 5245     (clear-stream $_test-input-buffered-file->buffer)
 5246     (clear-stream _test-output-stream)
 5247     (clear-stream $_test-output-buffered-file->buffer)
 5248     #
 5249     (write _test-input-stream "fn f {\n")
 5250     (write _test-input-stream "  var a: t\n")
 5251     (write _test-input-stream "  foo a\n")
 5252     (write _test-input-stream "}\n")
 5253     (write _test-input-stream "fn foo x: t {\n")
 5254     (write _test-input-stream "}\n")
 5255     (write _test-input-stream "type t {\n")
 5256     (write _test-input-stream "  x: int\n")
 5257     (write _test-input-stream "  y: int\n")
 5258     (write _test-input-stream "}\n")
 5259     # convert
 5260     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5261     (flush _test-output-buffered-file)
 5262 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5268     # check output
 5269     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5270     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5271     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5272     (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")
 5273     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5274     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5275     # var a: t
 5276     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 5277     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 5278     # foo a
 5279     (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")
 5280     #
 5281     (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")
 5282     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5283     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5284     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5285     (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")
 5286     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5287     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5288     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5289     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5290     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5291     (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")
 5292     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5293     (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")
 5294     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5295     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5296     # . epilogue
 5297     89/<- %esp 5/r32/ebp
 5298     5d/pop-to-ebp
 5299     c3/return
 5300 
 5301 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 5302     # . prologue
 5303     55/push-ebp
 5304     89/<- %ebp 4/r32/esp
 5305     # setup
 5306     (clear-stream _test-input-stream)
 5307     (clear-stream $_test-input-buffered-file->buffer)
 5308     (clear-stream _test-output-stream)
 5309     (clear-stream $_test-output-buffered-file->buffer)
 5310     #
 5311     (write _test-input-stream "fn f {\n")
 5312     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 5313     (write _test-input-stream "  foo *a\n")
 5314     (write _test-input-stream "}\n")
 5315     (write _test-input-stream "fn foo x: t {\n")
 5316     (write _test-input-stream "}\n")
 5317     (write _test-input-stream "type t {\n")
 5318     (write _test-input-stream "  x: int\n")
 5319     (write _test-input-stream "  y: int\n")
 5320     (write _test-input-stream "}\n")
 5321     # convert
 5322     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5323     (flush _test-output-buffered-file)
 5324 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5330     # check output
 5331     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 5332     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 5333     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 5334     (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")
 5335     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 5336     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 5337     # var a
 5338     (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")
 5339     (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")
 5340     # foo a
 5341     (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")
 5342     #
 5343     (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")
 5344     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 5345     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 5346     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 5347     (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")
 5348     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 5349     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 5350     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 5351     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 5352     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 5353     (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")
 5354     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 5355     (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")
 5356     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 5357     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 5358     # . epilogue
 5359     89/<- %esp 5/r32/ebp
 5360     5d/pop-to-ebp
 5361     c3/return
 5362 
 5363 # we don't have special support for call-by-reference; just explicitly create
 5364 # a new variable with the address of the arg
 5365 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 5366     # . prologue
 5367     55/push-ebp
 5368     89/<- %ebp 4/r32/esp
 5369     # setup
 5370     (clear-stream _test-input-stream)
 5371     (clear-stream $_test-input-buffered-file->buffer)
 5372     (clear-stream _test-output-stream)
 5373     (clear-stream $_test-output-buffered-file->buffer)
 5374     #
 5375     (write _test-input-stream "fn f {\n")
 5376     (write _test-input-stream "  var a: t\n")
 5377     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 5378     (write _test-input-stream "  foo b\n")
 5379     (write _test-input-stream "}\n")
 5380     (write _test-input-stream "fn foo x: (addr t) {\n")
 5381     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 5382     (write _test-input-stream "  increment *x\n")
 5383     (write _test-input-stream "}\n")
 5384     (write _test-input-stream "type t {\n")
 5385     (write _test-input-stream "  x: int\n")
 5386     (write _test-input-stream "  y: int\n")
 5387     (write _test-input-stream "}\n")
 5388     # convert
 5389     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5390     (flush _test-output-buffered-file)
 5391 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5397     # check output
 5398     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 5399     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 5400     (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")
 5401     (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")
 5402     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 5403     (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")
 5404     # var a: t
 5405     (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")
 5406     (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")
 5407     # var b/eax: (addr t)
 5408     (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")
 5409     (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")
 5410     # foo a
 5411     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 5412     #
 5413     (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")
 5414     (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")
 5415     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 5416     (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")
 5417     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 5418     (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")
 5419     (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")
 5420     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 5421     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 5422     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 5423     (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")
 5424     (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")
 5425     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 5426     (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")
 5427     (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")
 5428     (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")
 5429     (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")
 5430     (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")
 5431     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 5432     (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")
 5433     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 5434     (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")
 5435     (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")
 5436     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 5437     # . epilogue
 5438     89/<- %esp 5/r32/ebp
 5439     5d/pop-to-ebp
 5440     c3/return
 5441 
 5442 test-convert-get-on-local-variable:
 5443     # . prologue
 5444     55/push-ebp
 5445     89/<- %ebp 4/r32/esp
 5446     # setup
 5447     (clear-stream _test-input-stream)
 5448     (clear-stream $_test-input-buffered-file->buffer)
 5449     (clear-stream _test-output-stream)
 5450     (clear-stream $_test-output-buffered-file->buffer)
 5451     #
 5452     (write _test-input-stream "fn foo {\n")
 5453     (write _test-input-stream "  var a: t\n")
 5454     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5455     (write _test-input-stream "}\n")
 5456     (write _test-input-stream "type t {\n")
 5457     (write _test-input-stream "  x: int\n")
 5458     (write _test-input-stream "  y: int\n")
 5459     (write _test-input-stream "}\n")
 5460     # convert
 5461     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5462     (flush _test-output-buffered-file)
 5463 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5469     # check output
 5470     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 5471     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 5472     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 5473     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 5474     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 5475     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 5476     # var a
 5477     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 5478     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 5479     # var c
 5480     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 5481     # get
 5482     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 5483     # reclaim c
 5484     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 5485     # reclaim a
 5486     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 5487     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 5488     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 5489     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 5490     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 5491     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 5492     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 5493     # . epilogue
 5494     89/<- %esp 5/r32/ebp
 5495     5d/pop-to-ebp
 5496     c3/return
 5497 
 5498 test-convert-get-on-function-argument:
 5499     # . prologue
 5500     55/push-ebp
 5501     89/<- %ebp 4/r32/esp
 5502     # setup
 5503     (clear-stream _test-input-stream)
 5504     (clear-stream $_test-input-buffered-file->buffer)
 5505     (clear-stream _test-output-stream)
 5506     (clear-stream $_test-output-buffered-file->buffer)
 5507     #
 5508     (write _test-input-stream "fn foo a: t {\n")
 5509     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5510     (write _test-input-stream "}\n")
 5511     (write _test-input-stream "type t {\n")
 5512     (write _test-input-stream "  x: int\n")
 5513     (write _test-input-stream "  y: int\n")
 5514     (write _test-input-stream "}\n")
 5515     # convert
 5516     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5517     (flush _test-output-buffered-file)
 5518 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5524     # check output
 5525     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 5526     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 5527     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 5528     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 5529     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 5530     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 5531     # var c
 5532     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 5533     # get
 5534     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 5535     # reclaim c
 5536     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 5537     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 5538     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 5539     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 5540     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 5541     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 5542     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 5543     # . epilogue
 5544     89/<- %esp 5/r32/ebp
 5545     5d/pop-to-ebp
 5546     c3/return
 5547 
 5548 test-convert-get-on-function-argument-with-known-type:
 5549     # . prologue
 5550     55/push-ebp
 5551     89/<- %ebp 4/r32/esp
 5552     # setup
 5553     (clear-stream _test-input-stream)
 5554     (clear-stream $_test-input-buffered-file->buffer)
 5555     (clear-stream _test-output-stream)
 5556     (clear-stream $_test-output-buffered-file->buffer)
 5557     #
 5558     (write _test-input-stream "type t {\n")
 5559     (write _test-input-stream "  x: int\n")
 5560     (write _test-input-stream "  y: int\n")
 5561     (write _test-input-stream "}\n")
 5562     (write _test-input-stream "fn foo a: t {\n")
 5563     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5564     (write _test-input-stream "}\n")
 5565     # convert
 5566     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5567     (flush _test-output-buffered-file)
 5568 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5574     # check output
 5575     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 5576     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 5577     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 5578     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 5579     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 5580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 5581     # var c
 5582     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 5583     # get
 5584     (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")
 5585     # reclaim c
 5586     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 5587     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 5588     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 5589     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 5590     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 5591     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 5592     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 5593     # . epilogue
 5594     89/<- %esp 5/r32/ebp
 5595     5d/pop-to-ebp
 5596     c3/return
 5597 
 5598 test-add-with-too-many-inouts:
 5599     # . prologue
 5600     55/push-ebp
 5601     89/<- %ebp 4/r32/esp
 5602     # setup
 5603     (clear-stream _test-input-stream)
 5604     (clear-stream $_test-input-buffered-file->buffer)
 5605     (clear-stream _test-output-stream)
 5606     (clear-stream $_test-output-buffered-file->buffer)
 5607     (clear-stream _test-error-stream)
 5608     (clear-stream $_test-error-buffered-file->buffer)
 5609     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5610     68/push 0/imm32
 5611     68/push 0/imm32
 5612     89/<- %edx 4/r32/esp
 5613     (tailor-exit-descriptor %edx 0x10)
 5614     #
 5615     (write _test-input-stream "fn foo {\n")
 5616     (write _test-input-stream "  var a: int\n")
 5617     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 5618     (write _test-input-stream "}\n")
 5619     # convert
 5620     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5621     # registers except esp clobbered at this point
 5622     # restore ed
 5623     89/<- %edx 4/r32/esp
 5624     (flush _test-output-buffered-file)
 5625     (flush _test-error-buffered-file)
 5626 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5632     # check output
 5633     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 5634     (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")
 5635     # check that stop(1) was called
 5636     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 5637     # don't restore from ebp
 5638     81 0/subop/add %esp 8/imm32
 5639     # . epilogue
 5640     5d/pop-to-ebp
 5641     c3/return
 5642 
 5643 test-add-with-too-many-inouts-2:
 5644     # . prologue
 5645     55/push-ebp
 5646     89/<- %ebp 4/r32/esp
 5647     # setup
 5648     (clear-stream _test-input-stream)
 5649     (clear-stream $_test-input-buffered-file->buffer)
 5650     (clear-stream _test-output-stream)
 5651     (clear-stream $_test-output-buffered-file->buffer)
 5652     (clear-stream _test-error-stream)
 5653     (clear-stream $_test-error-buffered-file->buffer)
 5654     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5655     68/push 0/imm32
 5656     68/push 0/imm32
 5657     89/<- %edx 4/r32/esp
 5658     (tailor-exit-descriptor %edx 0x10)
 5659     #
 5660     (write _test-input-stream "fn foo {\n")
 5661     (write _test-input-stream "  var a: int\n")
 5662     (write _test-input-stream "  add-to a, 0, 1\n")
 5663     (write _test-input-stream "}\n")
 5664     # convert
 5665     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5666     # registers except esp clobbered at this point
 5667     # restore ed
 5668     89/<- %edx 4/r32/esp
 5669     (flush _test-output-buffered-file)
 5670     (flush _test-error-buffered-file)
 5671 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5677     # check output
 5678     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 5679     (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")
 5680     # check that stop(1) was called
 5681     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 5682     # don't restore from ebp
 5683     81 0/subop/add %esp 8/imm32
 5684     # . epilogue
 5685     5d/pop-to-ebp
 5686     c3/return
 5687 
 5688 test-add-with-too-many-outputs:
 5689     # . prologue
 5690     55/push-ebp
 5691     89/<- %ebp 4/r32/esp
 5692     # setup
 5693     (clear-stream _test-input-stream)
 5694     (clear-stream $_test-input-buffered-file->buffer)
 5695     (clear-stream _test-output-stream)
 5696     (clear-stream $_test-output-buffered-file->buffer)
 5697     (clear-stream _test-error-stream)
 5698     (clear-stream $_test-error-buffered-file->buffer)
 5699     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5700     68/push 0/imm32
 5701     68/push 0/imm32
 5702     89/<- %edx 4/r32/esp
 5703     (tailor-exit-descriptor %edx 0x10)
 5704     #
 5705     (write _test-input-stream "fn foo {\n")
 5706     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 5707     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 5708     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 5709     (write _test-input-stream "  c, b <- add a\n")
 5710     (write _test-input-stream "}\n")
 5711     # convert
 5712     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5713     # registers except esp clobbered at this point
 5714     # restore ed
 5715     89/<- %edx 4/r32/esp
 5716     (flush _test-output-buffered-file)
 5717     (flush _test-error-buffered-file)
 5718 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5724     # check output
 5725     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 5726     (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")
 5727     # check that stop(1) was called
 5728     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 5729     # don't restore from ebp
 5730     81 0/subop/add %esp 8/imm32
 5731     # . epilogue
 5732     5d/pop-to-ebp
 5733     c3/return
 5734 
 5735 test-add-with-non-number:
 5736     # . prologue
 5737     55/push-ebp
 5738     89/<- %ebp 4/r32/esp
 5739     # setup
 5740     (clear-stream _test-input-stream)
 5741     (clear-stream $_test-input-buffered-file->buffer)
 5742     (clear-stream _test-output-stream)
 5743     (clear-stream $_test-output-buffered-file->buffer)
 5744     (clear-stream _test-error-stream)
 5745     (clear-stream $_test-error-buffered-file->buffer)
 5746     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5747     68/push 0/imm32
 5748     68/push 0/imm32
 5749     89/<- %edx 4/r32/esp
 5750     (tailor-exit-descriptor %edx 0x10)
 5751     #
 5752     (write _test-input-stream "fn foo {\n")
 5753     (write _test-input-stream "  var a: int\n")
 5754     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 5755     (write _test-input-stream "}\n")
 5756     # convert
 5757     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5758     # registers except esp clobbered at this point
 5759     # restore ed
 5760     89/<- %edx 4/r32/esp
 5761     (flush _test-output-buffered-file)
 5762     (flush _test-error-buffered-file)
 5763 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5769     # check output
 5770     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5771     (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")
 5772     # check that stop(1) was called
 5773     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5774     # don't restore from ebp
 5775     81 0/subop/add %esp 8/imm32
 5776     # . epilogue
 5777     5d/pop-to-ebp
 5778     c3/return
 5779 
 5780 test-add-with-addr-dereferenced:
 5781     # . prologue
 5782     55/push-ebp
 5783     89/<- %ebp 4/r32/esp
 5784     # setup
 5785     (clear-stream _test-input-stream)
 5786     (clear-stream $_test-input-buffered-file->buffer)
 5787     (clear-stream _test-output-stream)
 5788     (clear-stream $_test-output-buffered-file->buffer)
 5789     #
 5790     (write _test-input-stream "fn foo {\n")
 5791     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5792     (write _test-input-stream "  add-to *a, 1\n")
 5793     (write _test-input-stream "}\n")
 5794     # convert
 5795     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5796     (flush _test-output-buffered-file)
 5797     # no error
 5798     # . epilogue
 5799     89/<- %esp 5/r32/ebp
 5800     5d/pop-to-ebp
 5801     c3/return
 5802 
 5803 test-get-with-wrong-field:
 5804     # . prologue
 5805     55/push-ebp
 5806     89/<- %ebp 4/r32/esp
 5807     # setup
 5808     (clear-stream _test-input-stream)
 5809     (clear-stream $_test-input-buffered-file->buffer)
 5810     (clear-stream _test-output-stream)
 5811     (clear-stream $_test-output-buffered-file->buffer)
 5812     (clear-stream _test-error-stream)
 5813     (clear-stream $_test-error-buffered-file->buffer)
 5814     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5815     68/push 0/imm32
 5816     68/push 0/imm32
 5817     89/<- %edx 4/r32/esp
 5818     (tailor-exit-descriptor %edx 0x10)
 5819     #
 5820     (write _test-input-stream "fn foo {\n")
 5821     (write _test-input-stream "  var a: t\n")
 5822     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5823     (write _test-input-stream "}\n")
 5824     (write _test-input-stream "type t {\n")
 5825     (write _test-input-stream "  x: int\n")
 5826     (write _test-input-stream "}\n")
 5827     # convert
 5828     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5829     # registers except esp clobbered at this point
 5830     # restore ed
 5831     89/<- %edx 4/r32/esp
 5832     (flush _test-output-buffered-file)
 5833     (flush _test-error-buffered-file)
 5834 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5840     # check output
 5841     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5842     (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")
 5843     # check that stop(1) was called
 5844     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5845     # don't restore from ebp
 5846     81 0/subop/add %esp 8/imm32
 5847     # . epilogue
 5848     5d/pop-to-ebp
 5849     c3/return
 5850 
 5851 test-get-with-wrong-base-type:
 5852     # . prologue
 5853     55/push-ebp
 5854     89/<- %ebp 4/r32/esp
 5855     # setup
 5856     (clear-stream _test-input-stream)
 5857     (clear-stream $_test-input-buffered-file->buffer)
 5858     (clear-stream _test-output-stream)
 5859     (clear-stream $_test-output-buffered-file->buffer)
 5860     (clear-stream _test-error-stream)
 5861     (clear-stream $_test-error-buffered-file->buffer)
 5862     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5863     68/push 0/imm32
 5864     68/push 0/imm32
 5865     89/<- %edx 4/r32/esp
 5866     (tailor-exit-descriptor %edx 0x10)
 5867     #
 5868     (write _test-input-stream "fn foo {\n")
 5869     (write _test-input-stream "  var a: int\n")
 5870     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5871     (write _test-input-stream "}\n")
 5872     # convert
 5873     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5874     # registers except esp clobbered at this point
 5875     # restore ed
 5876     89/<- %edx 4/r32/esp
 5877     (flush _test-output-buffered-file)
 5878     (flush _test-error-buffered-file)
 5879 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5885     # check output
 5886     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5887     (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")
 5888     # check that stop(1) was called
 5889     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5890     # don't restore from ebp
 5891     81 0/subop/add %esp 8/imm32
 5892     # . epilogue
 5893     5d/pop-to-ebp
 5894     c3/return
 5895 
 5896 test-get-with-wrong-base-type-2:
 5897     # . prologue
 5898     55/push-ebp
 5899     89/<- %ebp 4/r32/esp
 5900     # setup
 5901     (clear-stream _test-input-stream)
 5902     (clear-stream $_test-input-buffered-file->buffer)
 5903     (clear-stream _test-output-stream)
 5904     (clear-stream $_test-output-buffered-file->buffer)
 5905     (clear-stream _test-error-stream)
 5906     (clear-stream $_test-error-buffered-file->buffer)
 5907     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5908     68/push 0/imm32
 5909     68/push 0/imm32
 5910     89/<- %edx 4/r32/esp
 5911     (tailor-exit-descriptor %edx 0x10)
 5912     #
 5913     (write _test-input-stream "fn foo {\n")
 5914     (write _test-input-stream "  var a: (addr t)\n")
 5915     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5916     (write _test-input-stream "}\n")
 5917     (write _test-input-stream "type t {\n")
 5918     (write _test-input-stream "  x: int\n")
 5919     (write _test-input-stream "}\n")
 5920     # convert
 5921     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5922     # registers except esp clobbered at this point
 5923     # restore ed
 5924     89/<- %edx 4/r32/esp
 5925     (flush _test-output-buffered-file)
 5926     (flush _test-error-buffered-file)
 5927 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5933     # check output
 5934     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5935     (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")
 5936     # check that stop(1) was called
 5937     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5938     # don't restore from ebp
 5939     81 0/subop/add %esp 8/imm32
 5940     # . epilogue
 5941     5d/pop-to-ebp
 5942     c3/return
 5943 
 5944 test-get-with-wrong-offset-type:
 5945     # . prologue
 5946     55/push-ebp
 5947     89/<- %ebp 4/r32/esp
 5948     # setup
 5949     (clear-stream _test-input-stream)
 5950     (clear-stream $_test-input-buffered-file->buffer)
 5951     (clear-stream _test-output-stream)
 5952     (clear-stream $_test-output-buffered-file->buffer)
 5953     (clear-stream _test-error-stream)
 5954     (clear-stream $_test-error-buffered-file->buffer)
 5955     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5956     68/push 0/imm32
 5957     68/push 0/imm32
 5958     89/<- %edx 4/r32/esp
 5959     (tailor-exit-descriptor %edx 0x10)
 5960     #
 5961     (write _test-input-stream "fn foo {\n")
 5962     (write _test-input-stream "  var a: t\n")
 5963     (write _test-input-stream "  var b: int\n")
 5964     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5965     (write _test-input-stream "}\n")
 5966     (write _test-input-stream "type t {\n")
 5967     (write _test-input-stream "  x: int\n")
 5968     (write _test-input-stream "}\n")
 5969     # convert
 5970     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5971     # registers except esp clobbered at this point
 5972     # restore ed
 5973     89/<- %edx 4/r32/esp
 5974     (flush _test-output-buffered-file)
 5975     (flush _test-error-buffered-file)
 5976 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 5982     # check output
 5983     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5984     (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")
 5985     # check that stop(1) was called
 5986     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5987     # don't restore from ebp
 5988     81 0/subop/add %esp 8/imm32
 5989     # . epilogue
 5990     5d/pop-to-ebp
 5991     c3/return
 5992 
 5993 test-get-with-wrong-output-type:
 5994     # . prologue
 5995     55/push-ebp
 5996     89/<- %ebp 4/r32/esp
 5997     # setup
 5998     (clear-stream _test-input-stream)
 5999     (clear-stream $_test-input-buffered-file->buffer)
 6000     (clear-stream _test-output-stream)
 6001     (clear-stream $_test-output-buffered-file->buffer)
 6002     (clear-stream _test-error-stream)
 6003     (clear-stream $_test-error-buffered-file->buffer)
 6004     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6005     68/push 0/imm32
 6006     68/push 0/imm32
 6007     89/<- %edx 4/r32/esp
 6008     (tailor-exit-descriptor %edx 0x10)
 6009     #
 6010     (write _test-input-stream "fn foo {\n")
 6011     (write _test-input-stream "  var a: t\n")
 6012     (write _test-input-stream "  var c: (addr int)\n")
 6013     (write _test-input-stream "  c <- get a, x\n")
 6014     (write _test-input-stream "}\n")
 6015     (write _test-input-stream "type t {\n")
 6016     (write _test-input-stream "  x: int\n")
 6017     (write _test-input-stream "}\n")
 6018     # convert
 6019     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6020     # registers except esp clobbered at this point
 6021     # restore ed
 6022     89/<- %edx 4/r32/esp
 6023     (flush _test-output-buffered-file)
 6024     (flush _test-error-buffered-file)
 6025 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6031     # check output
 6032     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 6033     (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")
 6034     # check that stop(1) was called
 6035     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 6036     # don't restore from ebp
 6037     81 0/subop/add %esp 8/imm32
 6038     # . epilogue
 6039     5d/pop-to-ebp
 6040     c3/return
 6041 
 6042 test-get-with-wrong-output-type-2:
 6043     # . prologue
 6044     55/push-ebp
 6045     89/<- %ebp 4/r32/esp
 6046     # setup
 6047     (clear-stream _test-input-stream)
 6048     (clear-stream $_test-input-buffered-file->buffer)
 6049     (clear-stream _test-output-stream)
 6050     (clear-stream $_test-output-buffered-file->buffer)
 6051     (clear-stream _test-error-stream)
 6052     (clear-stream $_test-error-buffered-file->buffer)
 6053     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6054     68/push 0/imm32
 6055     68/push 0/imm32
 6056     89/<- %edx 4/r32/esp
 6057     (tailor-exit-descriptor %edx 0x10)
 6058     #
 6059     (write _test-input-stream "fn foo {\n")
 6060     (write _test-input-stream "  var a: t\n")
 6061     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 6062     (write _test-input-stream "}\n")
 6063     (write _test-input-stream "type t {\n")
 6064     (write _test-input-stream "  x: int\n")
 6065     (write _test-input-stream "}\n")
 6066     # convert
 6067     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6068     # registers except esp clobbered at this point
 6069     # restore ed
 6070     89/<- %edx 4/r32/esp
 6071     (flush _test-output-buffered-file)
 6072     (flush _test-error-buffered-file)
 6073 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6079     # check output
 6080     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 6081     (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")
 6082     # check that stop(1) was called
 6083     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 6084     # don't restore from ebp
 6085     81 0/subop/add %esp 8/imm32
 6086     # . epilogue
 6087     5d/pop-to-ebp
 6088     c3/return
 6089 
 6090 test-get-with-wrong-output-type-3:
 6091     # . prologue
 6092     55/push-ebp
 6093     89/<- %ebp 4/r32/esp
 6094     # setup
 6095     (clear-stream _test-input-stream)
 6096     (clear-stream $_test-input-buffered-file->buffer)
 6097     (clear-stream _test-output-stream)
 6098     (clear-stream $_test-output-buffered-file->buffer)
 6099     (clear-stream _test-error-stream)
 6100     (clear-stream $_test-error-buffered-file->buffer)
 6101     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6102     68/push 0/imm32
 6103     68/push 0/imm32
 6104     89/<- %edx 4/r32/esp
 6105     (tailor-exit-descriptor %edx 0x10)
 6106     #
 6107     (write _test-input-stream "fn foo {\n")
 6108     (write _test-input-stream "  var a: t\n")
 6109     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 6110     (write _test-input-stream "}\n")
 6111     (write _test-input-stream "type t {\n")
 6112     (write _test-input-stream "  x: int\n")
 6113     (write _test-input-stream "}\n")
 6114     # convert
 6115     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6116     # registers except esp clobbered at this point
 6117     # restore ed
 6118     89/<- %edx 4/r32/esp
 6119     (flush _test-output-buffered-file)
 6120     (flush _test-error-buffered-file)
 6121 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6127     # check output
 6128     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 6129     (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")
 6130     # check that stop(1) was called
 6131     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 6132     # don't restore from ebp
 6133     81 0/subop/add %esp 8/imm32
 6134     # . epilogue
 6135     5d/pop-to-ebp
 6136     c3/return
 6137 
 6138 test-get-with-wrong-output-type-4:
 6139     # . prologue
 6140     55/push-ebp
 6141     89/<- %ebp 4/r32/esp
 6142     # setup
 6143     (clear-stream _test-input-stream)
 6144     (clear-stream $_test-input-buffered-file->buffer)
 6145     (clear-stream _test-output-stream)
 6146     (clear-stream $_test-output-buffered-file->buffer)
 6147     (clear-stream _test-error-stream)
 6148     (clear-stream $_test-error-buffered-file->buffer)
 6149     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6150     68/push 0/imm32
 6151     68/push 0/imm32
 6152     89/<- %edx 4/r32/esp
 6153     (tailor-exit-descriptor %edx 0x10)
 6154     #
 6155     (write _test-input-stream "fn foo {\n")
 6156     (write _test-input-stream "  var a: t\n")
 6157     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 6158     (write _test-input-stream "}\n")
 6159     (write _test-input-stream "type t {\n")
 6160     (write _test-input-stream "  x: int\n")
 6161     (write _test-input-stream "}\n")
 6162     # convert
 6163     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6164     # registers except esp clobbered at this point
 6165     # restore ed
 6166     89/<- %edx 4/r32/esp
 6167     (flush _test-output-buffered-file)
 6168     (flush _test-error-buffered-file)
 6169 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6175     # check output
 6176     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 6177     (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")
 6178     # check that stop(1) was called
 6179     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 6180     # don't restore from ebp
 6181     81 0/subop/add %esp 8/imm32
 6182     # . epilogue
 6183     5d/pop-to-ebp
 6184     c3/return
 6185 
 6186 test-get-with-wrong-output-type-5:
 6187     # . prologue
 6188     55/push-ebp
 6189     89/<- %ebp 4/r32/esp
 6190     # setup
 6191     (clear-stream _test-input-stream)
 6192     (clear-stream $_test-input-buffered-file->buffer)
 6193     (clear-stream _test-output-stream)
 6194     (clear-stream $_test-output-buffered-file->buffer)
 6195     #
 6196     (write _test-input-stream "fn foo {\n")
 6197     (write _test-input-stream "  var a: t\n")
 6198     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 6199     (write _test-input-stream "}\n")
 6200     (write _test-input-stream "type t {\n")
 6201     (write _test-input-stream "  x: (handle int)\n")
 6202     (write _test-input-stream "}\n")
 6203     # convert
 6204     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6205     (flush _test-output-buffered-file)
 6206     # no errors
 6207     # . epilogue
 6208     89/<- %esp 5/r32/ebp
 6209     5d/pop-to-ebp
 6210     c3/return
 6211 
 6212 test-get-with-too-few-inouts:
 6213     # . prologue
 6214     55/push-ebp
 6215     89/<- %ebp 4/r32/esp
 6216     # setup
 6217     (clear-stream _test-input-stream)
 6218     (clear-stream $_test-input-buffered-file->buffer)
 6219     (clear-stream _test-output-stream)
 6220     (clear-stream $_test-output-buffered-file->buffer)
 6221     (clear-stream _test-error-stream)
 6222     (clear-stream $_test-error-buffered-file->buffer)
 6223     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6224     68/push 0/imm32
 6225     68/push 0/imm32
 6226     89/<- %edx 4/r32/esp
 6227     (tailor-exit-descriptor %edx 0x10)
 6228     #
 6229     (write _test-input-stream "fn foo {\n")
 6230     (write _test-input-stream "  var a: t\n")
 6231     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 6232     (write _test-input-stream "}\n")
 6233     (write _test-input-stream "type t {\n")
 6234     (write _test-input-stream "  x: int\n")
 6235     (write _test-input-stream "}\n")
 6236     # convert
 6237     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6238     # registers except esp clobbered at this point
 6239     # restore ed
 6240     89/<- %edx 4/r32/esp
 6241     (flush _test-output-buffered-file)
 6242     (flush _test-error-buffered-file)
 6243 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6249     # check output
 6250     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 6251     (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")
 6252     # check that stop(1) was called
 6253     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 6254     # don't restore from ebp
 6255     81 0/subop/add %esp 8/imm32
 6256     # . epilogue
 6257     5d/pop-to-ebp
 6258     c3/return
 6259 
 6260 test-get-with-too-many-inouts:
 6261     # . prologue
 6262     55/push-ebp
 6263     89/<- %ebp 4/r32/esp
 6264     # setup
 6265     (clear-stream _test-input-stream)
 6266     (clear-stream $_test-input-buffered-file->buffer)
 6267     (clear-stream _test-output-stream)
 6268     (clear-stream $_test-output-buffered-file->buffer)
 6269     (clear-stream _test-error-stream)
 6270     (clear-stream $_test-error-buffered-file->buffer)
 6271     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6272     68/push 0/imm32
 6273     68/push 0/imm32
 6274     89/<- %edx 4/r32/esp
 6275     (tailor-exit-descriptor %edx 0x10)
 6276     #
 6277     (write _test-input-stream "fn foo {\n")
 6278     (write _test-input-stream "  var a: t\n")
 6279     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 6280     (write _test-input-stream "}\n")
 6281     (write _test-input-stream "type t {\n")
 6282     (write _test-input-stream "  x: int\n")
 6283     (write _test-input-stream "}\n")
 6284     # convert
 6285     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6286     # registers except esp clobbered at this point
 6287     # restore ed
 6288     89/<- %edx 4/r32/esp
 6289     (flush _test-output-buffered-file)
 6290     (flush _test-error-buffered-file)
 6291 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6297     # check output
 6298     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 6299     (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")
 6300     # check that stop(1) was called
 6301     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 6302     # don't restore from ebp
 6303     81 0/subop/add %esp 8/imm32
 6304     # . epilogue
 6305     5d/pop-to-ebp
 6306     c3/return
 6307 
 6308 test-get-with-no-output:
 6309     # . prologue
 6310     55/push-ebp
 6311     89/<- %ebp 4/r32/esp
 6312     # setup
 6313     (clear-stream _test-input-stream)
 6314     (clear-stream $_test-input-buffered-file->buffer)
 6315     (clear-stream _test-output-stream)
 6316     (clear-stream $_test-output-buffered-file->buffer)
 6317     (clear-stream _test-error-stream)
 6318     (clear-stream $_test-error-buffered-file->buffer)
 6319     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6320     68/push 0/imm32
 6321     68/push 0/imm32
 6322     89/<- %edx 4/r32/esp
 6323     (tailor-exit-descriptor %edx 0x10)
 6324     #
 6325     (write _test-input-stream "fn foo {\n")
 6326     (write _test-input-stream "  var a: t\n")
 6327     (write _test-input-stream "  get a, x\n")
 6328     (write _test-input-stream "}\n")
 6329     (write _test-input-stream "type t {\n")
 6330     (write _test-input-stream "  x: int\n")
 6331     (write _test-input-stream "}\n")
 6332     # convert
 6333     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6334     # registers except esp clobbered at this point
 6335     # restore ed
 6336     89/<- %edx 4/r32/esp
 6337     (flush _test-output-buffered-file)
 6338     (flush _test-error-buffered-file)
 6339 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6345     # check output
 6346     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 6347     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 6348     # check that stop(1) was called
 6349     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 6350     # don't restore from ebp
 6351     81 0/subop/add %esp 8/imm32
 6352     # . epilogue
 6353     5d/pop-to-ebp
 6354     c3/return
 6355 
 6356 test-get-with-too-many-outputs:
 6357     # . prologue
 6358     55/push-ebp
 6359     89/<- %ebp 4/r32/esp
 6360     # setup
 6361     (clear-stream _test-input-stream)
 6362     (clear-stream $_test-input-buffered-file->buffer)
 6363     (clear-stream _test-output-stream)
 6364     (clear-stream $_test-output-buffered-file->buffer)
 6365     (clear-stream _test-error-stream)
 6366     (clear-stream $_test-error-buffered-file->buffer)
 6367     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6368     68/push 0/imm32
 6369     68/push 0/imm32
 6370     89/<- %edx 4/r32/esp
 6371     (tailor-exit-descriptor %edx 0x10)
 6372     #
 6373     (write _test-input-stream "fn foo {\n")
 6374     (write _test-input-stream "  var a: t\n")
 6375     (write _test-input-stream "  var b: int\n")
 6376     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 6377     (write _test-input-stream "  c, b <- get a, x\n")
 6378     (write _test-input-stream "}\n")
 6379     (write _test-input-stream "type t {\n")
 6380     (write _test-input-stream "  x: int\n")
 6381     (write _test-input-stream "}\n")
 6382     # convert
 6383     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6384     # registers except esp clobbered at this point
 6385     # restore ed
 6386     89/<- %edx 4/r32/esp
 6387     (flush _test-output-buffered-file)
 6388     (flush _test-error-buffered-file)
 6389 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6395     # check output
 6396     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 6397     (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")
 6398     # check that stop(1) was called
 6399     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 6400     # don't restore from ebp
 6401     81 0/subop/add %esp 8/imm32
 6402     # . epilogue
 6403     5d/pop-to-ebp
 6404     c3/return
 6405 
 6406 test-convert-array-of-user-defined-types:
 6407     # . prologue
 6408     55/push-ebp
 6409     89/<- %ebp 4/r32/esp
 6410     # setup
 6411     (clear-stream _test-input-stream)
 6412     (clear-stream $_test-input-buffered-file->buffer)
 6413     (clear-stream _test-output-stream)
 6414     (clear-stream $_test-output-buffered-file->buffer)
 6415     #
 6416     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6417     (write _test-input-stream "  x: int\n")
 6418     (write _test-input-stream "  y: int\n")
 6419     (write _test-input-stream "}\n")
 6420     (write _test-input-stream "fn foo {\n")
 6421     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6422     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 6423     (write _test-input-stream "  var x/eax: (addr t) <- index arr, idx\n")
 6424     (write _test-input-stream "}\n")
 6425     # convert
 6426     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6427     (flush _test-output-buffered-file)
 6428 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6434     # check output
 6435     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 6436     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 6437     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 6438     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 6439     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 6440     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 6441     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 6442     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 6443     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 6444     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 6445     (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")
 6446     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 6447     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 6448     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 6449     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 6450     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 6451     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 6452     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 6453     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 6454     # . epilogue
 6455     89/<- %esp 5/r32/ebp
 6456     5d/pop-to-ebp
 6457     c3/return
 6458 
 6459 test-convert-length-of-array-of-user-defined-types-to-eax:
 6460     # . prologue
 6461     55/push-ebp
 6462     89/<- %ebp 4/r32/esp
 6463     # setup
 6464     (clear-stream _test-input-stream)
 6465     (clear-stream $_test-input-buffered-file->buffer)
 6466     (clear-stream _test-output-stream)
 6467     (clear-stream $_test-output-buffered-file->buffer)
 6468     #
 6469     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6470     (write _test-input-stream "  x: int\n")
 6471     (write _test-input-stream "  y: int\n")
 6472     (write _test-input-stream "  z: int\n")
 6473     (write _test-input-stream "}\n")
 6474     (write _test-input-stream "fn foo {\n")
 6475     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6476     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 6477     (write _test-input-stream "}\n")
 6478     # convert
 6479     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6480     (flush _test-output-buffered-file)
 6481 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6487     # check output
 6488     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 6489     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 6490     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 6491     (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")
 6492     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 6493     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 6494     # var arr
 6495     (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")
 6496     (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")
 6497     # length instruction
 6498     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 6499     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 6500     (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")
 6501     (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")
 6502     (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")
 6503     (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")
 6504     (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")
 6505     (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")
 6506     # reclaim arr
 6507     (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")
 6508     #
 6509     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 6510     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 6511     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 6512     (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")
 6513     (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")
 6514     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 6515     # . epilogue
 6516     89/<- %esp 5/r32/ebp
 6517     5d/pop-to-ebp
 6518     c3/return
 6519 
 6520 test-convert-length-of-array-of-user-defined-types-to-ecx:
 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     #
 6530     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6531     (write _test-input-stream "  x: int\n")
 6532     (write _test-input-stream "  y: int\n")
 6533     (write _test-input-stream "  z: int\n")
 6534     (write _test-input-stream "}\n")
 6535     (write _test-input-stream "fn foo {\n")
 6536     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6537     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 6538     (write _test-input-stream "}\n")
 6539     # convert
 6540     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6541     (flush _test-output-buffered-file)
 6542 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6548     # check output
 6549     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 6550     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 6551     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 6552     (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")
 6553     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 6554     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 6555     # var a
 6556     (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")
 6557     (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")
 6558     # var x
 6559     (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")
 6560     # length instruction
 6561     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 6562     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 6563     (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")
 6564     (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")
 6565     (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")
 6566     (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")
 6567     (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")
 6568     (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")
 6569     (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")
 6570     # reclaim x
 6571     (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")
 6572     # reclaim a
 6573     (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")
 6574     #
 6575     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 6576     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 6577     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 6578     (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")
 6579     (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")
 6580     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 6581     # . epilogue
 6582     89/<- %esp 5/r32/ebp
 6583     5d/pop-to-ebp
 6584     c3/return
 6585 
 6586 test-convert-length-of-array-of-user-defined-types-to-edx:
 6587     # . prologue
 6588     55/push-ebp
 6589     89/<- %ebp 4/r32/esp
 6590     # setup
 6591     (clear-stream _test-input-stream)
 6592     (clear-stream $_test-input-buffered-file->buffer)
 6593     (clear-stream _test-output-stream)
 6594     (clear-stream $_test-output-buffered-file->buffer)
 6595     #
 6596     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 6597     (write _test-input-stream "  x: int\n")
 6598     (write _test-input-stream "  y: int\n")
 6599     (write _test-input-stream "  z: int\n")
 6600     (write _test-input-stream "}\n")
 6601     (write _test-input-stream "fn foo {\n")
 6602     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6603     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 6604     (write _test-input-stream "}\n")
 6605     # convert
 6606     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6607     (flush _test-output-buffered-file)
 6608 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6614     # check output
 6615     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 6616     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 6617     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 6618     (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")
 6619     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 6620     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 6621     # var a
 6622     (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")
 6623     (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")
 6624     # var x
 6625     (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")
 6626     # length instruction
 6627     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 6628     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 6629     (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")
 6630     (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")
 6631     (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")
 6632     (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")
 6633     (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")
 6634     (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")
 6635     (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")
 6636     # reclaim x
 6637     (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")
 6638     # reclaim a
 6639     (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")
 6640     #
 6641     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 6642     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 6643     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 6644     (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")
 6645     (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")
 6646     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 6647     # . epilogue
 6648     89/<- %esp 5/r32/ebp
 6649     5d/pop-to-ebp
 6650     c3/return
 6651 
 6652 test-convert-length-of-array-of-user-defined-types:
 6653     # . prologue
 6654     55/push-ebp
 6655     89/<- %ebp 4/r32/esp
 6656     # setup
 6657     (clear-stream _test-input-stream)
 6658     (clear-stream $_test-input-buffered-file->buffer)
 6659     (clear-stream _test-output-stream)
 6660     (clear-stream $_test-output-buffered-file->buffer)
 6661     #
 6662     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 6663     (write _test-input-stream "  x: int\n")
 6664     (write _test-input-stream "  y: int\n")
 6665     (write _test-input-stream "  z: int\n")
 6666     (write _test-input-stream "}\n")
 6667     (write _test-input-stream "fn foo {\n")
 6668     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 6669     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 6670     (write _test-input-stream "}\n")
 6671     # convert
 6672     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 6673     (flush _test-output-buffered-file)
 6674 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6680     # check output
 6681     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 6682     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 6683     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 6684     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 6685     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 6686     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 6687     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 6688     (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")
 6689     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 6690     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 6691     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 6692     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 6693     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 6694     (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")
 6695     (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")
 6696     (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")
 6697     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 6698     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 6699     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 6700     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 6701     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 6702     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 6703     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 6704     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 6705     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 6706     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 6707     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 6708     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 6709     # . epilogue
 6710     89/<- %esp 5/r32/ebp
 6711     5d/pop-to-ebp
 6712     c3/return
 6713 
 6714 test-index-with-non-array-atom-base-type:
 6715     # . prologue
 6716     55/push-ebp
 6717     89/<- %ebp 4/r32/esp
 6718     # setup
 6719     (clear-stream _test-input-stream)
 6720     (clear-stream $_test-input-buffered-file->buffer)
 6721     (clear-stream _test-output-stream)
 6722     (clear-stream $_test-output-buffered-file->buffer)
 6723     (clear-stream _test-error-stream)
 6724     (clear-stream $_test-error-buffered-file->buffer)
 6725     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6726     68/push 0/imm32
 6727     68/push 0/imm32
 6728     89/<- %edx 4/r32/esp
 6729     (tailor-exit-descriptor %edx 0x10)
 6730     #
 6731     (write _test-input-stream "fn foo {\n")
 6732     (write _test-input-stream "  var a: int\n")
 6733     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6734     (write _test-input-stream "}\n")
 6735     # convert
 6736     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6737     # registers except esp clobbered at this point
 6738     # restore ed
 6739     89/<- %edx 4/r32/esp
 6740     (flush _test-output-buffered-file)
 6741     (flush _test-error-buffered-file)
 6742 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6748     # check output
 6749     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-atom-base-type: output should be empty")
 6750     (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")
 6751     # check that stop(1) was called
 6752     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status")
 6753     # don't restore from ebp
 6754     81 0/subop/add %esp 8/imm32
 6755     # . epilogue
 6756     5d/pop-to-ebp
 6757     c3/return
 6758 
 6759 test-index-with-non-array-compound-base-type:
 6760     # . prologue
 6761     55/push-ebp
 6762     89/<- %ebp 4/r32/esp
 6763     # setup
 6764     (clear-stream _test-input-stream)
 6765     (clear-stream $_test-input-buffered-file->buffer)
 6766     (clear-stream _test-output-stream)
 6767     (clear-stream $_test-output-buffered-file->buffer)
 6768     (clear-stream _test-error-stream)
 6769     (clear-stream $_test-error-buffered-file->buffer)
 6770     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6771     68/push 0/imm32
 6772     68/push 0/imm32
 6773     89/<- %edx 4/r32/esp
 6774     (tailor-exit-descriptor %edx 0x10)
 6775     #
 6776     (write _test-input-stream "fn foo {\n")
 6777     (write _test-input-stream "  var a: (handle int)\n")
 6778     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6779     (write _test-input-stream "}\n")
 6780     # convert
 6781     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6782     # registers except esp clobbered at this point
 6783     # restore ed
 6784     89/<- %edx 4/r32/esp
 6785     (flush _test-output-buffered-file)
 6786     (flush _test-error-buffered-file)
 6787 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6793     # check output
 6794     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type: output should be empty")
 6795     (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")
 6796     # check that stop(1) was called
 6797     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status")
 6798     # don't restore from ebp
 6799     81 0/subop/add %esp 8/imm32
 6800     # . epilogue
 6801     5d/pop-to-ebp
 6802     c3/return
 6803 
 6804 test-index-with-non-array-compound-base-type-2:
 6805     # . prologue
 6806     55/push-ebp
 6807     89/<- %ebp 4/r32/esp
 6808     # setup
 6809     (clear-stream _test-input-stream)
 6810     (clear-stream $_test-input-buffered-file->buffer)
 6811     (clear-stream _test-output-stream)
 6812     (clear-stream $_test-output-buffered-file->buffer)
 6813     (clear-stream _test-error-stream)
 6814     (clear-stream $_test-error-buffered-file->buffer)
 6815     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6816     68/push 0/imm32
 6817     68/push 0/imm32
 6818     89/<- %edx 4/r32/esp
 6819     (tailor-exit-descriptor %edx 0x10)
 6820     #
 6821     (write _test-input-stream "fn foo {\n")
 6822     (write _test-input-stream "  var a: (addr int)\n")
 6823     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6824     (write _test-input-stream "}\n")
 6825     # convert
 6826     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6827     # registers except esp clobbered at this point
 6828     # restore ed
 6829     89/<- %edx 4/r32/esp
 6830     (flush _test-output-buffered-file)
 6831     (flush _test-error-buffered-file)
 6832 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6838     # check output
 6839     (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type-2: output should be empty")
 6840     (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")
 6841     # check that stop(1) was called
 6842     (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status")
 6843     # don't restore from ebp
 6844     81 0/subop/add %esp 8/imm32
 6845     # . epilogue
 6846     5d/pop-to-ebp
 6847     c3/return
 6848 
 6849 test-index-with-array-atom-base-type:
 6850     # . prologue
 6851     55/push-ebp
 6852     89/<- %ebp 4/r32/esp
 6853     # setup
 6854     (clear-stream _test-input-stream)
 6855     (clear-stream $_test-input-buffered-file->buffer)
 6856     (clear-stream _test-output-stream)
 6857     (clear-stream $_test-output-buffered-file->buffer)
 6858     (clear-stream _test-error-stream)
 6859     (clear-stream $_test-error-buffered-file->buffer)
 6860     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6861     68/push 0/imm32
 6862     68/push 0/imm32
 6863     89/<- %edx 4/r32/esp
 6864     (tailor-exit-descriptor %edx 0x10)
 6865     #
 6866     (write _test-input-stream "fn foo {\n")
 6867     (write _test-input-stream "  var a: array\n")
 6868     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6869     (write _test-input-stream "}\n")
 6870     # convert
 6871     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6872     # registers except esp clobbered at this point
 6873     # restore ed
 6874     89/<- %edx 4/r32/esp
 6875     (flush _test-output-buffered-file)
 6876     (flush _test-error-buffered-file)
 6877 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6883     # check output
 6884     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-atom-base-type: output should be empty")
 6885     (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")
 6886     # check that stop(1) was called
 6887     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status")
 6888     # don't restore from ebp
 6889     81 0/subop/add %esp 8/imm32
 6890     # . epilogue
 6891     5d/pop-to-ebp
 6892     c3/return
 6893 
 6894 test-index-with-addr-base-on-stack:
 6895     # . prologue
 6896     55/push-ebp
 6897     89/<- %ebp 4/r32/esp
 6898     # setup
 6899     (clear-stream _test-input-stream)
 6900     (clear-stream $_test-input-buffered-file->buffer)
 6901     (clear-stream _test-output-stream)
 6902     (clear-stream $_test-output-buffered-file->buffer)
 6903     (clear-stream _test-error-stream)
 6904     (clear-stream $_test-error-buffered-file->buffer)
 6905     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6906     68/push 0/imm32
 6907     68/push 0/imm32
 6908     89/<- %edx 4/r32/esp
 6909     (tailor-exit-descriptor %edx 0x10)
 6910     #
 6911     (write _test-input-stream "fn foo {\n")
 6912     (write _test-input-stream "  var a: (addr array int)\n")
 6913     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6914     (write _test-input-stream "}\n")
 6915     # convert
 6916     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6917     # registers except esp clobbered at this point
 6918     # restore ed
 6919     89/<- %edx 4/r32/esp
 6920     (flush _test-output-buffered-file)
 6921     (flush _test-error-buffered-file)
 6922 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6928     # check output
 6929     (check-stream-equal _test-output-stream  ""  "F - test-index-with-addr-base-on-stack: output should be empty")
 6930     (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")
 6931     # check that stop(1) was called
 6932     (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status")
 6933     # don't restore from ebp
 6934     81 0/subop/add %esp 8/imm32
 6935     # . epilogue
 6936     5d/pop-to-ebp
 6937     c3/return
 6938 
 6939 test-index-with-array-base-in-register:
 6940     # . prologue
 6941     55/push-ebp
 6942     89/<- %ebp 4/r32/esp
 6943     # setup
 6944     (clear-stream _test-input-stream)
 6945     (clear-stream $_test-input-buffered-file->buffer)
 6946     (clear-stream _test-output-stream)
 6947     (clear-stream $_test-output-buffered-file->buffer)
 6948     (clear-stream _test-error-stream)
 6949     (clear-stream $_test-error-buffered-file->buffer)
 6950     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6951     68/push 0/imm32
 6952     68/push 0/imm32
 6953     89/<- %edx 4/r32/esp
 6954     (tailor-exit-descriptor %edx 0x10)
 6955     #
 6956     (write _test-input-stream "fn foo {\n")
 6957     (write _test-input-stream "  var a/eax: (array int 3) <- copy 0\n")
 6958     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
 6959     (write _test-input-stream "}\n")
 6960     # convert
 6961     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 6962     # registers except esp clobbered at this point
 6963     # restore ed
 6964     89/<- %edx 4/r32/esp
 6965     (flush _test-output-buffered-file)
 6966     (flush _test-error-buffered-file)
 6967 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 6973     # check output
 6974     (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-base-in-register: output should be empty")
 6975     (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")
 6976     # check that stop(1) was called
 6977     (check-ints-equal *(edx+4) 2 "F - test-index-with-array-base-in-register: exit status")
 6978     # don't restore from ebp
 6979     81 0/subop/add %esp 8/imm32
 6980     # . epilogue
 6981     5d/pop-to-ebp
 6982     c3/return
 6983 
 6984 test-index-with-wrong-index-type:
 6985     # . prologue
 6986     55/push-ebp
 6987     89/<- %ebp 4/r32/esp
 6988     # setup
 6989     (clear-stream _test-input-stream)
 6990     (clear-stream $_test-input-buffered-file->buffer)
 6991     (clear-stream _test-output-stream)
 6992     (clear-stream $_test-output-buffered-file->buffer)
 6993     (clear-stream _test-error-stream)
 6994     (clear-stream $_test-error-buffered-file->buffer)
 6995     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 6996     68/push 0/imm32
 6997     68/push 0/imm32
 6998     89/<- %edx 4/r32/esp
 6999     (tailor-exit-descriptor %edx 0x10)
 7000     #
 7001     (write _test-input-stream "fn foo {\n")
 7002     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7003     (write _test-input-stream "  var b: boolean\n")
 7004     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7005     (write _test-input-stream "}\n")
 7006     # convert
 7007     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7008     # registers except esp clobbered at this point
 7009     # restore ed
 7010     89/<- %edx 4/r32/esp
 7011     (flush _test-output-buffered-file)
 7012     (flush _test-error-buffered-file)
 7013 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7019     # check output
 7020     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-index-type: output should be empty")
 7021     (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")
 7022     # check that stop(1) was called
 7023     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status")
 7024     # don't restore from ebp
 7025     81 0/subop/add %esp 8/imm32
 7026     # . epilogue
 7027     5d/pop-to-ebp
 7028     c3/return
 7029 
 7030 test-index-with-offset-atom-index-type:
 7031     # . prologue
 7032     55/push-ebp
 7033     89/<- %ebp 4/r32/esp
 7034     # setup
 7035     (clear-stream _test-input-stream)
 7036     (clear-stream $_test-input-buffered-file->buffer)
 7037     (clear-stream _test-output-stream)
 7038     (clear-stream $_test-output-buffered-file->buffer)
 7039     (clear-stream _test-error-stream)
 7040     (clear-stream $_test-error-buffered-file->buffer)
 7041     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7042     68/push 0/imm32
 7043     68/push 0/imm32
 7044     89/<- %edx 4/r32/esp
 7045     (tailor-exit-descriptor %edx 0x10)
 7046     #
 7047     (write _test-input-stream "fn foo {\n")
 7048     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7049     (write _test-input-stream "  var b: offset\n")
 7050     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7051     (write _test-input-stream "}\n")
 7052     # convert
 7053     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7054     # registers except esp clobbered at this point
 7055     # restore ed
 7056     89/<- %edx 4/r32/esp
 7057     (flush _test-output-buffered-file)
 7058     (flush _test-error-buffered-file)
 7059 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7065     # check output
 7066     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-atom-index-type: output should be empty")
 7067     (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")
 7068     # check that stop(1) was called
 7069     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status")
 7070     # don't restore from ebp
 7071     81 0/subop/add %esp 8/imm32
 7072     # . epilogue
 7073     5d/pop-to-ebp
 7074     c3/return
 7075 
 7076 test-index-with-offset-on-stack:
 7077     # . prologue
 7078     55/push-ebp
 7079     89/<- %ebp 4/r32/esp
 7080     # setup
 7081     (clear-stream _test-input-stream)
 7082     (clear-stream $_test-input-buffered-file->buffer)
 7083     (clear-stream _test-output-stream)
 7084     (clear-stream $_test-output-buffered-file->buffer)
 7085     (clear-stream _test-error-stream)
 7086     (clear-stream $_test-error-buffered-file->buffer)
 7087     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7088     68/push 0/imm32
 7089     68/push 0/imm32
 7090     89/<- %edx 4/r32/esp
 7091     (tailor-exit-descriptor %edx 0x10)
 7092     #
 7093     (write _test-input-stream "fn foo {\n")
 7094     (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
 7095     (write _test-input-stream "  var b: int\n")
 7096     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7097     (write _test-input-stream "}\n")
 7098     # convert
 7099     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7100     # registers except esp clobbered at this point
 7101     # restore ed
 7102     89/<- %edx 4/r32/esp
 7103     (flush _test-output-buffered-file)
 7104     (flush _test-error-buffered-file)
 7105 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7111     # check output
 7112     (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-on-stack: output should be empty")
 7113     (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")
 7114     # check that stop(1) was called
 7115     (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status")
 7116     # don't restore from ebp
 7117     81 0/subop/add %esp 8/imm32
 7118     # . epilogue
 7119     5d/pop-to-ebp
 7120     c3/return
 7121 
 7122 test-index-needs-offset-type:
 7123     # . prologue
 7124     55/push-ebp
 7125     89/<- %ebp 4/r32/esp
 7126     # setup
 7127     (clear-stream _test-input-stream)
 7128     (clear-stream $_test-input-buffered-file->buffer)
 7129     (clear-stream _test-output-stream)
 7130     (clear-stream $_test-output-buffered-file->buffer)
 7131     (clear-stream _test-error-stream)
 7132     (clear-stream $_test-error-buffered-file->buffer)
 7133     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7134     68/push 0/imm32
 7135     68/push 0/imm32
 7136     89/<- %edx 4/r32/esp
 7137     (tailor-exit-descriptor %edx 0x10)
 7138     #
 7139     (write _test-input-stream "fn foo {\n")
 7140     (write _test-input-stream "  var a/eax: (addr array t) <- copy 0\n")
 7141     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 7142     (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
 7143     (write _test-input-stream "}\n")
 7144     (write _test-input-stream "type t {\n")  # size 12 is not a power of two
 7145     (write _test-input-stream "  x: int\n")
 7146     (write _test-input-stream "  y: int\n")
 7147     (write _test-input-stream "  z: int\n")
 7148     (write _test-input-stream "}\n")
 7149     # convert
 7150     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7151     # registers except esp clobbered at this point
 7152     # restore ed
 7153     89/<- %edx 4/r32/esp
 7154     (flush _test-output-buffered-file)
 7155     (flush _test-error-buffered-file)
 7156 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7162     # check output
 7163     (check-stream-equal _test-output-stream  ""  "F - test-index-needs-offset-type: output should be empty")
 7164     (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")
 7165     # check that stop(1) was called
 7166     (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: exit status")
 7167     # don't restore from ebp
 7168     81 0/subop/add %esp 8/imm32
 7169     # . epilogue
 7170     5d/pop-to-ebp
 7171     c3/return
 7172 
 7173 test-index-with-output-not-address:
 7174     # . prologue
 7175     55/push-ebp
 7176     89/<- %ebp 4/r32/esp
 7177     # setup
 7178     (clear-stream _test-input-stream)
 7179     (clear-stream $_test-input-buffered-file->buffer)
 7180     (clear-stream _test-output-stream)
 7181     (clear-stream $_test-output-buffered-file->buffer)
 7182     (clear-stream _test-error-stream)
 7183     (clear-stream $_test-error-buffered-file->buffer)
 7184     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7185     68/push 0/imm32
 7186     68/push 0/imm32
 7187     89/<- %edx 4/r32/esp
 7188     (tailor-exit-descriptor %edx 0x10)
 7189     #
 7190     (write _test-input-stream "fn foo {\n")
 7191     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7192     (write _test-input-stream "  var o/edi: int <- index a, 0\n")
 7193     (write _test-input-stream "}\n")
 7194     # convert
 7195     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7196     # registers except esp clobbered at this point
 7197     # restore ed
 7198     89/<- %edx 4/r32/esp
 7199     (flush _test-output-buffered-file)
 7200     (flush _test-error-buffered-file)
 7201 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7207     # check output
 7208     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address: output should be empty")
 7209     (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")
 7210     # check that stop(1) was called
 7211     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status")
 7212     # don't restore from ebp
 7213     81 0/subop/add %esp 8/imm32
 7214     # . epilogue
 7215     5d/pop-to-ebp
 7216     c3/return
 7217 
 7218 test-index-with-output-not-address-2:
 7219     # . prologue
 7220     55/push-ebp
 7221     89/<- %ebp 4/r32/esp
 7222     # setup
 7223     (clear-stream _test-input-stream)
 7224     (clear-stream $_test-input-buffered-file->buffer)
 7225     (clear-stream _test-output-stream)
 7226     (clear-stream $_test-output-buffered-file->buffer)
 7227     (clear-stream _test-error-stream)
 7228     (clear-stream $_test-error-buffered-file->buffer)
 7229     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7230     68/push 0/imm32
 7231     68/push 0/imm32
 7232     89/<- %edx 4/r32/esp
 7233     (tailor-exit-descriptor %edx 0x10)
 7234     #
 7235     (write _test-input-stream "fn foo {\n")
 7236     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7237     (write _test-input-stream "  var o/edi: (int) <- index a, 0\n")
 7238     (write _test-input-stream "}\n")
 7239     # convert
 7240     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7241     # registers except esp clobbered at this point
 7242     # restore ed
 7243     89/<- %edx 4/r32/esp
 7244     (flush _test-output-buffered-file)
 7245     (flush _test-error-buffered-file)
 7246 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7252     # check output
 7253     (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address-2: output should be empty")
 7254     (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")
 7255     # check that stop(1) was called
 7256     (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status")
 7257     # don't restore from ebp
 7258     81 0/subop/add %esp 8/imm32
 7259     # . epilogue
 7260     5d/pop-to-ebp
 7261     c3/return
 7262 
 7263 test-index-with-wrong-output-type:
 7264     # . prologue
 7265     55/push-ebp
 7266     89/<- %ebp 4/r32/esp
 7267     # setup
 7268     (clear-stream _test-input-stream)
 7269     (clear-stream $_test-input-buffered-file->buffer)
 7270     (clear-stream _test-output-stream)
 7271     (clear-stream $_test-output-buffered-file->buffer)
 7272     (clear-stream _test-error-stream)
 7273     (clear-stream $_test-error-buffered-file->buffer)
 7274     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7275     68/push 0/imm32
 7276     68/push 0/imm32
 7277     89/<- %edx 4/r32/esp
 7278     (tailor-exit-descriptor %edx 0x10)
 7279     #
 7280     (write _test-input-stream "fn foo {\n")
 7281     (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
 7282     (write _test-input-stream "  var o/edi: (addr int) <- index a, 0\n")
 7283     (write _test-input-stream "}\n")
 7284     # convert
 7285     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7286     # registers except esp clobbered at this point
 7287     # restore ed
 7288     89/<- %edx 4/r32/esp
 7289     (flush _test-output-buffered-file)
 7290     (flush _test-error-buffered-file)
 7291 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7297     # check output
 7298     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-type: output should be empty")
 7299     (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")
 7300     # check that stop(1) was called
 7301     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status")
 7302     # don't restore from ebp
 7303     81 0/subop/add %esp 8/imm32
 7304     # . epilogue
 7305     5d/pop-to-ebp
 7306     c3/return
 7307 
 7308 test-index-with-wrong-output-compound-type:
 7309     # . prologue
 7310     55/push-ebp
 7311     89/<- %ebp 4/r32/esp
 7312     # setup
 7313     (clear-stream _test-input-stream)
 7314     (clear-stream $_test-input-buffered-file->buffer)
 7315     (clear-stream _test-output-stream)
 7316     (clear-stream $_test-output-buffered-file->buffer)
 7317     (clear-stream _test-error-stream)
 7318     (clear-stream $_test-error-buffered-file->buffer)
 7319     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7320     68/push 0/imm32
 7321     68/push 0/imm32
 7322     89/<- %edx 4/r32/esp
 7323     (tailor-exit-descriptor %edx 0x10)
 7324     #
 7325     (write _test-input-stream "fn foo {\n")
 7326     (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
 7327     (write _test-input-stream "  var o/edi: (addr handle int) <- index a, 0\n")
 7328     (write _test-input-stream "}\n")
 7329     # convert
 7330     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7331     # registers except esp clobbered at this point
 7332     # restore ed
 7333     89/<- %edx 4/r32/esp
 7334     (flush _test-output-buffered-file)
 7335     (flush _test-error-buffered-file)
 7336 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7342     # check output
 7343     (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-compound-type: output should be empty")
 7344     (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")
 7345     # check that stop(1) was called
 7346     (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status")
 7347     # don't restore from ebp
 7348     81 0/subop/add %esp 8/imm32
 7349     # . epilogue
 7350     5d/pop-to-ebp
 7351     c3/return
 7352 
 7353 test-index-with-no-inouts:
 7354     # . prologue
 7355     55/push-ebp
 7356     89/<- %ebp 4/r32/esp
 7357     # setup
 7358     (clear-stream _test-input-stream)
 7359     (clear-stream $_test-input-buffered-file->buffer)
 7360     (clear-stream _test-output-stream)
 7361     (clear-stream $_test-output-buffered-file->buffer)
 7362     (clear-stream _test-error-stream)
 7363     (clear-stream $_test-error-buffered-file->buffer)
 7364     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7365     68/push 0/imm32
 7366     68/push 0/imm32
 7367     89/<- %edx 4/r32/esp
 7368     (tailor-exit-descriptor %edx 0x10)
 7369     #
 7370     (write _test-input-stream "fn foo {\n")
 7371     (write _test-input-stream "  var c/ecx: (addr int) <- index\n")
 7372     (write _test-input-stream "}\n")
 7373     # convert
 7374     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7375     # registers except esp clobbered at this point
 7376     # restore ed
 7377     89/<- %edx 4/r32/esp
 7378     (flush _test-output-buffered-file)
 7379     (flush _test-error-buffered-file)
 7380 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7386     # check output
 7387     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-inouts: output should be empty")
 7388     (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")
 7389     # check that stop(1) was called
 7390     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status")
 7391     # don't restore from ebp
 7392     81 0/subop/add %esp 8/imm32
 7393     # . epilogue
 7394     5d/pop-to-ebp
 7395     c3/return
 7396 
 7397 test-index-with-too-few-inouts:
 7398     # . prologue
 7399     55/push-ebp
 7400     89/<- %ebp 4/r32/esp
 7401     # setup
 7402     (clear-stream _test-input-stream)
 7403     (clear-stream $_test-input-buffered-file->buffer)
 7404     (clear-stream _test-output-stream)
 7405     (clear-stream $_test-output-buffered-file->buffer)
 7406     (clear-stream _test-error-stream)
 7407     (clear-stream $_test-error-buffered-file->buffer)
 7408     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7409     68/push 0/imm32
 7410     68/push 0/imm32
 7411     89/<- %edx 4/r32/esp
 7412     (tailor-exit-descriptor %edx 0x10)
 7413     #
 7414     (write _test-input-stream "fn foo {\n")
 7415     (write _test-input-stream "  var a: (array int 3)\n")
 7416     (write _test-input-stream "  var c/ecx: (addr int) <- index a\n")
 7417     (write _test-input-stream "}\n")
 7418     # convert
 7419     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7420     # registers except esp clobbered at this point
 7421     # restore ed
 7422     89/<- %edx 4/r32/esp
 7423     (flush _test-output-buffered-file)
 7424     (flush _test-error-buffered-file)
 7425 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7431     # check output
 7432     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-few-inouts: output should be empty")
 7433     (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")
 7434     # check that stop(1) was called
 7435     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status")
 7436     # don't restore from ebp
 7437     81 0/subop/add %esp 8/imm32
 7438     # . epilogue
 7439     5d/pop-to-ebp
 7440     c3/return
 7441 
 7442 test-index-with-too-many-inouts:
 7443     # . prologue
 7444     55/push-ebp
 7445     89/<- %ebp 4/r32/esp
 7446     # setup
 7447     (clear-stream _test-input-stream)
 7448     (clear-stream $_test-input-buffered-file->buffer)
 7449     (clear-stream _test-output-stream)
 7450     (clear-stream $_test-output-buffered-file->buffer)
 7451     (clear-stream _test-error-stream)
 7452     (clear-stream $_test-error-buffered-file->buffer)
 7453     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7454     68/push 0/imm32
 7455     68/push 0/imm32
 7456     89/<- %edx 4/r32/esp
 7457     (tailor-exit-descriptor %edx 0x10)
 7458     #
 7459     (write _test-input-stream "fn foo {\n")
 7460     (write _test-input-stream "  var a: (array int 3)\n")
 7461     (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0, 0\n")
 7462     (write _test-input-stream "}\n")
 7463     # convert
 7464     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7465     # registers except esp clobbered at this point
 7466     # restore ed
 7467     89/<- %edx 4/r32/esp
 7468     (flush _test-output-buffered-file)
 7469     (flush _test-error-buffered-file)
 7470 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7476     # check output
 7477     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-inouts: output should be empty")
 7478     (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")
 7479     # check that stop(1) was called
 7480     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status")
 7481     # don't restore from ebp
 7482     81 0/subop/add %esp 8/imm32
 7483     # . epilogue
 7484     5d/pop-to-ebp
 7485     c3/return
 7486 
 7487 test-index-with-no-output:
 7488     # . prologue
 7489     55/push-ebp
 7490     89/<- %ebp 4/r32/esp
 7491     # setup
 7492     (clear-stream _test-input-stream)
 7493     (clear-stream $_test-input-buffered-file->buffer)
 7494     (clear-stream _test-output-stream)
 7495     (clear-stream $_test-output-buffered-file->buffer)
 7496     (clear-stream _test-error-stream)
 7497     (clear-stream $_test-error-buffered-file->buffer)
 7498     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7499     68/push 0/imm32
 7500     68/push 0/imm32
 7501     89/<- %edx 4/r32/esp
 7502     (tailor-exit-descriptor %edx 0x10)
 7503     #
 7504     (write _test-input-stream "fn foo {\n")
 7505     (write _test-input-stream "  var a: (array int 3)\n")
 7506     (write _test-input-stream "  index a, 0\n")
 7507     (write _test-input-stream "}\n")
 7508     # convert
 7509     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7510     # registers except esp clobbered at this point
 7511     # restore ed
 7512     89/<- %edx 4/r32/esp
 7513     (flush _test-output-buffered-file)
 7514     (flush _test-error-buffered-file)
 7515 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7521     # check output
 7522     (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-output: output should be empty")
 7523     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: must have an output"  "F - test-index-with-no-output: error message")
 7524     # check that stop(1) was called
 7525     (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status")
 7526     # don't restore from ebp
 7527     81 0/subop/add %esp 8/imm32
 7528     # . epilogue
 7529     5d/pop-to-ebp
 7530     c3/return
 7531 
 7532 test-index-with-too-many-outputs:
 7533     # . prologue
 7534     55/push-ebp
 7535     89/<- %ebp 4/r32/esp
 7536     # setup
 7537     (clear-stream _test-input-stream)
 7538     (clear-stream $_test-input-buffered-file->buffer)
 7539     (clear-stream _test-output-stream)
 7540     (clear-stream $_test-output-buffered-file->buffer)
 7541     (clear-stream _test-error-stream)
 7542     (clear-stream $_test-error-buffered-file->buffer)
 7543     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 7544     68/push 0/imm32
 7545     68/push 0/imm32
 7546     89/<- %edx 4/r32/esp
 7547     (tailor-exit-descriptor %edx 0x10)
 7548     #
 7549     (write _test-input-stream "fn foo {\n")
 7550     (write _test-input-stream "  var a: (array int 3)\n")
 7551     (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
 7552     (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
 7553     (write _test-input-stream "  b, c <- index a, 0\n")
 7554     (write _test-input-stream "}\n")
 7555     # convert
 7556     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 7557     # registers except esp clobbered at this point
 7558     # restore ed
 7559     89/<- %edx 4/r32/esp
 7560     (flush _test-output-buffered-file)
 7561     (flush _test-error-buffered-file)
 7562 +--  6 lines: #?     # dump _test-error-stream ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7568     # check output
 7569     (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-outputs: output should be empty")
 7570     (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")
 7571     # check that stop(1) was called
 7572     (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status")
 7573     # don't restore from ebp
 7574     81 0/subop/add %esp 8/imm32
 7575     # . epilogue
 7576     5d/pop-to-ebp
 7577     c3/return
 7578 
 7579 #######################################################
 7580 # Parsing
 7581 #######################################################
 7582 
 7583 == data
 7584 
 7585 # Global state added to each var record when parsing a function
 7586 Next-block-index:  # (addr int)
 7587     1/imm32
 7588 
 7589 Curr-block-depth:  # (addr int)
 7590     1/imm32
 7591 
 7592 == code
 7593 
 7594 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 7595     # pseudocode
 7596     #   var curr-function: (addr handle function) = Program->functions
 7597     #   var curr-signature: (addr handle function) = Program->signatures
 7598     #   var curr-type: (addr handle typeinfo) = Program->types
 7599     #   var line: (stream byte 512)
 7600     #   var word-slice: slice
 7601     #   while true                                  # line loop
 7602     #     clear-stream(line)
 7603     #     read-line-buffered(in, line)
 7604     #     if (line->write == 0) break               # end of file
 7605     #     word-slice = next-mu-token(line)
 7606     #     if slice-empty?(word-slice)               # end of line
 7607     #       continue
 7608     #     else if slice-starts-with?(word-slice, "#")  # comment
 7609     #       continue                                # end of line
 7610     #     else if slice-equal?(word-slice, "fn")
 7611     #       var new-function: (handle function) = allocate(function)
 7612     #       var vars: (stack live-var 256)
 7613     #       populate-mu-function-header(line, new-function, vars)
 7614     #       populate-mu-function-body(in, new-function, vars)
 7615     #       assert(vars->top == 0)
 7616     #       *curr-function = new-function
 7617     #       curr-function = &new-function->next
 7618     #     else if slice-equal?(word-slice, "sig")
 7619     #       var new-function: (handle function) = allocate(function)
 7620     #       populate-mu-function-signature(line, new-function)
 7621     #       *curr-signature = new-function
 7622     #       curr-signature = &new-function->next
 7623     #     else if slice-equal?(word-slice, "type")
 7624     #       word-slice = next-mu-token(line)
 7625     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 7626     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 7627     #       assert(next-word(line) == "{")
 7628     #       populate-mu-type(in, new-type)
 7629     #     else
 7630     #       abort()
 7631     #
 7632     # . prologue
 7633     55/push-ebp
 7634     89/<- %ebp 4/r32/esp
 7635     # var curr-signature: (addr handle function) at *(ebp-4)
 7636     68/push _Program-signatures/imm32
 7637     # . save registers
 7638     50/push-eax
 7639     51/push-ecx
 7640     52/push-edx
 7641     53/push-ebx
 7642     56/push-esi
 7643     57/push-edi
 7644     # var line/ecx: (stream byte 512)
 7645     81 5/subop/subtract %esp 0x200/imm32
 7646     68/push 0x200/imm32/size
 7647     68/push 0/imm32/read
 7648     68/push 0/imm32/write
 7649     89/<- %ecx 4/r32/esp
 7650     # var word-slice/edx: slice
 7651     68/push 0/imm32/end
 7652     68/push 0/imm32/start
 7653     89/<- %edx 4/r32/esp
 7654     # var curr-function/edi: (addr handle function)
 7655     bf/copy-to-edi _Program-functions/imm32
 7656     # var vars/ebx: (stack live-var 256)
 7657     81 5/subop/subtract %esp 0xc00/imm32
 7658     68/push 0xc00/imm32/size
 7659     68/push 0/imm32/top
 7660     89/<- %ebx 4/r32/esp
 7661     {
 7662 $parse-mu:line-loop:
 7663       (clear-stream %ecx)
 7664       (read-line-buffered *(ebp+8) %ecx)
 7665       # if (line->write == 0) break
 7666       81 7/subop/compare *ecx 0/imm32
 7667       0f 84/jump-if-= break/disp32
 7668 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7674       (next-mu-token %ecx %edx)
 7675       # if slice-empty?(word-slice) continue
 7676       (slice-empty? %edx)  # => eax
 7677       3d/compare-eax-and 0/imm32/false
 7678       0f 85/jump-if-!= loop/disp32
 7679       # if (*word-slice->start == "#") continue
 7680       # . eax = *word-slice->start
 7681       8b/-> *edx 0/r32/eax
 7682       8a/copy-byte *eax 0/r32/AL
 7683       81 4/subop/and %eax 0xff/imm32
 7684       # . if (eax == '#') continue
 7685       3d/compare-eax-and 0x23/imm32/hash
 7686       0f 84/jump-if-= loop/disp32
 7687       # if (slice-equal?(word-slice, "fn")) parse a function
 7688       {
 7689 $parse-mu:fn:
 7690         (slice-equal? %edx "fn")  # => eax
 7691         3d/compare-eax-and 0/imm32/false
 7692         0f 84/jump-if-= break/disp32
 7693         # var new-function/esi: (handle function)
 7694         68/push 0/imm32
 7695         68/push 0/imm32
 7696         89/<- %esi 4/r32/esp
 7697         # populate-mu-function(line, in, vars, new-function)
 7698         (allocate Heap *Function-size %esi)
 7699         # var new-function-addr/eax: (addr function)
 7700         (lookup *esi *(esi+4))  # => eax
 7701         # initialize vars
 7702         (clear-stack %ebx)
 7703         #
 7704         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7705         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 7706         # *curr-function = new-function
 7707         8b/-> *esi 0/r32/eax
 7708         89/<- *edi 0/r32/eax
 7709         8b/-> *(esi+4) 0/r32/eax
 7710         89/<- *(edi+4) 0/r32/eax
 7711         # curr-function = &new-function->next
 7712         # . var tmp/eax: (addr function) = lookup(new-function)
 7713         (lookup *esi *(esi+4))  # => eax
 7714         # . curr-function = &tmp->next
 7715         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 7716         # reclaim new-function
 7717         81 0/subop/add %esp 8/imm32
 7718         #
 7719         e9/jump $parse-mu:line-loop/disp32
 7720       }
 7721       # if (slice-equal?(word-slice, "sig")) parse a function signature
 7722       # Function signatures are for providing types to SubX functions.
 7723       {
 7724 $parse-mu:sig:
 7725         (slice-equal? %edx "sig")  # => eax
 7726         3d/compare-eax-and 0/imm32/false
 7727         0f 84/jump-if-= break/disp32
 7728         # edi = curr-function
 7729         57/push-edi
 7730         8b/-> *(ebp-4) 7/r32/edi
 7731         # var new-function/esi: (handle function)
 7732         68/push 0/imm32
 7733         68/push 0/imm32
 7734         89/<- %esi 4/r32/esp
 7735         # populate-mu-function(line, in, vars, new-function)
 7736         (allocate Heap *Function-size %esi)
 7737         # var new-function-addr/eax: (addr function)
 7738         (lookup *esi *(esi+4))  # => eax
 7739         #
 7740         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 7741         # *curr-signature = new-function
 7742         8b/-> *esi 0/r32/eax
 7743         89/<- *edi 0/r32/eax
 7744         8b/-> *(esi+4) 0/r32/eax
 7745         89/<- *(edi+4) 0/r32/eax
 7746         # curr-signature = &new-function->next
 7747         # . var tmp/eax: (addr function) = lookup(new-function)
 7748         (lookup *esi *(esi+4))  # => eax
 7749         # . curr-function = &tmp->next
 7750         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 7751         # reclaim new-function
 7752         81 0/subop/add %esp 8/imm32
 7753         # save curr-function
 7754         89/<- *(ebp-4) 7/r32/edi
 7755         # restore edi
 7756         5f/pop-to-edi
 7757         #
 7758         e9/jump $parse-mu:line-loop/disp32
 7759       }
 7760       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 7761       {
 7762 $parse-mu:type:
 7763         (slice-equal? %edx "type")  # => eax
 7764         3d/compare-eax-and 0/imm32
 7765         0f 84/jump-if-= break/disp32
 7766         (next-mu-token %ecx %edx)
 7767         # var type-id/eax: int
 7768         (pos-or-insert-slice Type-id %edx)  # => eax
 7769         # spill
 7770         51/push-ecx
 7771         # var new-type/ecx: (handle typeinfo)
 7772         68/push 0/imm32
 7773         68/push 0/imm32
 7774         89/<- %ecx 4/r32/esp
 7775         (find-or-create-typeinfo %eax %ecx)
 7776         #
 7777         (lookup *ecx *(ecx+4))  # => eax
 7778         # TODO: ensure that 'line' has nothing else but '{'
 7779 #? (dump-typeinfos "=== aaa\n")
 7780         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 7781 #? (dump-typeinfos "=== zzz\n")
 7782         # reclaim new-type
 7783         81 0/subop/add %esp 8/imm32
 7784         # restore
 7785         59/pop-to-ecx
 7786         e9/jump $parse-mu:line-loop/disp32
 7787       }
 7788       # otherwise abort
 7789       e9/jump $parse-mu:error1/disp32
 7790     } # end line loop
 7791 $parse-mu:end:
 7792     # . reclaim locals
 7793     81 0/subop/add %esp 0x20c/imm32  # line
 7794     81 0/subop/add %esp 0xc08/imm32  # vars
 7795     81 0/subop/add %esp 8/imm32
 7796     # . restore registers
 7797     5f/pop-to-edi
 7798     5e/pop-to-esi
 7799     5b/pop-to-ebx
 7800     5a/pop-to-edx
 7801     59/pop-to-ecx
 7802     58/pop-to-eax
 7803     # . reclaim local
 7804     81 0/subop/add %esp 4/imm32
 7805     # . epilogue
 7806     89/<- %esp 5/r32/ebp
 7807     5d/pop-to-ebp
 7808     c3/return
 7809 
 7810 $parse-mu:error1:
 7811     # error("unexpected top-level command: " word-slice "\n")
 7812     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 7813     (write-slice-buffered *(ebp+0xc) %edx)
 7814     (write-buffered *(ebp+0xc) "\n")
 7815     (flush *(ebp+0xc))
 7816     (stop *(ebp+0x10) 1)
 7817     # never gets here
 7818 
 7819 $parse-mu:error2:
 7820     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 7821     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 7822     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 7823     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 7824     (write-buffered *(ebp+0xc) "'\n")
 7825     (flush *(ebp+0xc))
 7826     (stop *(ebp+0x10) 1)
 7827     # never gets here
 7828 
 7829 # scenarios considered:
 7830 # ✗ fn foo  # no block
 7831 # ✓ fn foo {
 7832 # ✗ fn foo { {
 7833 # ✗ fn foo { }
 7834 # ✗ fn foo { } {
 7835 # ✗ fn foo x {
 7836 # ✗ fn foo x: {
 7837 # ✓ fn foo x: int {
 7838 # ✓ fn foo x: int {
 7839 # ✓ fn foo x: int -> y/eax: int {
 7840 # TODO:
 7841 #   disallow outputs of type `(... addr ...)`
 7842 #   disallow inputs of type `(... addr ... addr ...)`
 7843 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)
 7844     # pseudocode:
 7845     #   var word-slice: slice
 7846     #   next-mu-token(first-line, word-slice)
 7847     #   if slice-empty?(word-slice) abort
 7848     #   assert(word-slice not in '{' '}' '->')
 7849     #   out->name = slice-to-string(word-slice)
 7850     #   ## inouts
 7851     #   while true
 7852     #     word-slice = next-mu-token(first-line)
 7853     #     if slice-empty?(word-slice) abort
 7854     #     if (word-slice == '{') goto done
 7855     #     if (word-slice == '->') break
 7856     #     assert(word-slice != '}')
 7857     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7858     #     assert(v->register == null)
 7859     #     # v->block-depth is implicitly 0
 7860     #     out->inouts = append(v, out->inouts)
 7861     #     push(vars, {v, false})
 7862     #   ## outputs
 7863     #   while true
 7864     #     word-slice = next-mu-token(first-line)
 7865     #     if slice-empty?(word-slice) abort
 7866     #     if (word-slice == '{') break
 7867     #     assert(word-slice not in '}' '->')
 7868     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 7869     #     assert(v->register != null)
 7870     #     out->outputs = append(v, out->outputs)
 7871     #   done:
 7872     #
 7873     # . prologue
 7874     55/push-ebp
 7875     89/<- %ebp 4/r32/esp
 7876     # . save registers
 7877     50/push-eax
 7878     51/push-ecx
 7879     52/push-edx
 7880     53/push-ebx
 7881     57/push-edi
 7882     # edi = out
 7883     8b/-> *(ebp+0xc) 7/r32/edi
 7884     # var word-slice/ecx: slice
 7885     68/push 0/imm32/end
 7886     68/push 0/imm32/start
 7887     89/<- %ecx 4/r32/esp
 7888     # var v/ebx: (handle var)
 7889     68/push 0/imm32
 7890     68/push 0/imm32
 7891     89/<- %ebx 4/r32/esp
 7892     # read function name
 7893     (next-mu-token *(ebp+8) %ecx)
 7894     # error checking
 7895     # if slice-empty?(word-slice) abort
 7896     (slice-empty? %ecx)  # => eax
 7897     3d/compare-eax-and 0/imm32/false
 7898     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7899     # if (word-slice == '{') abort
 7900     (slice-equal? %ecx "{")   # => eax
 7901     3d/compare-eax-and 0/imm32/false
 7902     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7903     # if (word-slice == '->') abort
 7904     (slice-equal? %ecx "->")   # => eax
 7905     3d/compare-eax-and 0/imm32/false
 7906     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7907     # if (word-slice == '}') abort
 7908     (slice-equal? %ecx "}")   # => eax
 7909     3d/compare-eax-and 0/imm32/false
 7910     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7911     # save function name
 7912     (slice-to-string Heap %ecx %edi)  # Function-name
 7913     # save function inouts
 7914     {
 7915 $populate-mu-function-header:check-for-inout:
 7916       (next-mu-token *(ebp+8) %ecx)
 7917       # if slice-empty?(word-slice) abort
 7918       (slice-empty? %ecx)  # => eax
 7919       3d/compare-eax-and 0/imm32/false
 7920       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7921       # if (word-slice == '{') goto done
 7922       (slice-equal? %ecx "{")   # => eax
 7923       3d/compare-eax-and 0/imm32/false
 7924       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 7925       # if (word-slice == '->') break
 7926       (slice-equal? %ecx "->")   # => eax
 7927       3d/compare-eax-and 0/imm32/false
 7928       0f 85/jump-if-!= break/disp32
 7929       # if (word-slice == '}') abort
 7930       (slice-equal? %ecx "}")   # => eax
 7931       3d/compare-eax-and 0/imm32/false
 7932       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7933       # v = parse-var-with-type(word-slice, first-line)
 7934       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 7935       # assert(v->register == null)
 7936       # . eax: (addr var) = lookup(v)
 7937       (lookup *ebx *(ebx+4))  # => eax
 7938       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7939       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 7940       # v->block-depth is implicitly 0
 7941       #
 7942       # out->inouts = append(v, out->inouts)
 7943       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 7944       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 7945       # push(vars, {v, false})
 7946       (push *(ebp+0x10) *ebx)
 7947       (push *(ebp+0x10) *(ebx+4))
 7948       (push *(ebp+0x10) 0)  # false
 7949       #
 7950       e9/jump loop/disp32
 7951     }
 7952     # save function outputs
 7953     {
 7954 $populate-mu-function-header:check-for-out:
 7955       (next-mu-token *(ebp+8) %ecx)
 7956       # if slice-empty?(word-slice) abort
 7957       (slice-empty? %ecx)  # => eax
 7958       3d/compare-eax-and 0/imm32/false
 7959       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7960       # if (word-slice == '{') break
 7961       (slice-equal? %ecx "{")   # => eax
 7962       3d/compare-eax-and 0/imm32/false
 7963       0f 85/jump-if-!= break/disp32
 7964       # if (word-slice == '->') abort
 7965       (slice-equal? %ecx "->")   # => eax
 7966       3d/compare-eax-and 0/imm32/false
 7967       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7968       # if (word-slice == '}') abort
 7969       (slice-equal? %ecx "}")   # => eax
 7970       3d/compare-eax-and 0/imm32/false
 7971       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 7972       # v = parse-var-with-type(word-slice, first-line)
 7973       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 7974       # assert(var->register != null)
 7975       # . eax: (addr var) = lookup(v)
 7976       (lookup *ebx *(ebx+4))  # => eax
 7977       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 7978       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 7979       # out->outputs = append(v, out->outputs)
 7980       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 7981       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 7982       #
 7983       e9/jump loop/disp32
 7984     }
 7985 $populate-mu-function-header:done:
 7986     (check-no-tokens-left *(ebp+8))
 7987 $populate-mu-function-header:end:
 7988     # . reclaim locals
 7989     81 0/subop/add %esp 0x10/imm32
 7990     # . restore registers
 7991     5f/pop-to-edi
 7992     5b/pop-to-ebx
 7993     5a/pop-to-edx
 7994     59/pop-to-ecx
 7995     58/pop-to-eax
 7996     # . epilogue
 7997     89/<- %esp 5/r32/ebp
 7998     5d/pop-to-ebp
 7999     c3/return
 8000 
 8001 $populate-mu-function-header:error1:
 8002     # error("function header not in form 'fn <name> {'")
 8003     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 8004     (flush *(ebp+0x14))
 8005     (rewind-stream *(ebp+8))
 8006     (write-stream-data *(ebp+0x14) *(ebp+8))
 8007     (write-buffered *(ebp+0x14) "'\n")
 8008     (flush *(ebp+0x14))
 8009     (stop *(ebp+0x18) 1)
 8010     # never gets here
 8011 
 8012 $populate-mu-function-header:error2:
 8013     # error("fn " fn ": function inout '" var "' cannot be in a register")
 8014     (write-buffered *(ebp+0x14) "fn ")
 8015     50/push-eax
 8016     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8017     (write-buffered *(ebp+0x14) %eax)
 8018     58/pop-to-eax
 8019     (write-buffered *(ebp+0x14) ": function inout '")
 8020     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8021     (write-buffered *(ebp+0x10) %eax)
 8022     (write-buffered *(ebp+0x14) "' cannot be in a register")
 8023     (flush *(ebp+0x14))
 8024     (stop *(ebp+0x18) 1)
 8025     # never gets here
 8026 
 8027 $populate-mu-function-header:error3:
 8028     # error("fn " fn ": function output '" var "' must be in a register")
 8029     (write-buffered *(ebp+0x14) "fn ")
 8030     50/push-eax
 8031     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8032     (write-buffered *(ebp+0x14) %eax)
 8033     58/pop-to-eax
 8034     (write-buffered *(ebp+0x14) ": function output '")
 8035     (lookup *ebx *(ebx+4))  # => eax
 8036     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8037     (write-buffered *(ebp+0x14) %eax)
 8038     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 8039     (rewind-stream *(ebp+8))
 8040     (write-stream-data *(ebp+0x14) *(ebp+8))
 8041     (write-buffered *(ebp+0x14) "'\n")
 8042     (flush *(ebp+0x14))
 8043     (stop *(ebp+0x18) 1)
 8044     # never gets here
 8045 
 8046 # scenarios considered:
 8047 # ✓ fn foo
 8048 # ✗ fn foo {
 8049 # ✓ fn foo x
 8050 # ✓ fn foo x: int
 8051 # ✓ fn foo x: int -> y/eax: int
 8052 # TODO:
 8053 #   disallow outputs of type `(... addr ...)`
 8054 #   disallow inputs of type `(... addr ... addr ...)`
 8055 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8056     # pseudocode:
 8057     #   var word-slice: slice
 8058     #   next-mu-token(first-line, word-slice)
 8059     #   assert(word-slice not in '{' '}' '->')
 8060     #   out->name = slice-to-string(word-slice)
 8061     #   ## inouts
 8062     #   while true
 8063     #     word-slice = next-mu-token(first-line)
 8064     #     if slice-empty?(word-slice) break
 8065     #     if (word-slice == '->') break
 8066     #     assert(word-slice not in '{' '}')
 8067     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8068     #     assert(v->register == null)
 8069     #     # v->block-depth is implicitly 0
 8070     #     out->inouts = append(v, out->inouts)
 8071     #   ## outputs
 8072     #   while true
 8073     #     word-slice = next-mu-token(first-line)
 8074     #     if slice-empty?(word-slice) break
 8075     #     assert(word-slice not in '{' '}' '->')
 8076     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 8077     #     assert(v->register != null)
 8078     #     out->outputs = append(v, out->outputs)
 8079     #
 8080     # . prologue
 8081     55/push-ebp
 8082     89/<- %ebp 4/r32/esp
 8083     # . save registers
 8084     50/push-eax
 8085     51/push-ecx
 8086     52/push-edx
 8087     53/push-ebx
 8088     57/push-edi
 8089     # edi = out
 8090     8b/-> *(ebp+0xc) 7/r32/edi
 8091     # var word-slice/ecx: slice
 8092     68/push 0/imm32/end
 8093     68/push 0/imm32/start
 8094     89/<- %ecx 4/r32/esp
 8095     # var v/ebx: (handle var)
 8096     68/push 0/imm32
 8097     68/push 0/imm32
 8098     89/<- %ebx 4/r32/esp
 8099     # read function name
 8100     (next-mu-token *(ebp+8) %ecx)
 8101     # error checking
 8102     # if (word-slice == '{') abort
 8103     (slice-equal? %ecx "{")   # => eax
 8104     3d/compare-eax-and 0/imm32/false
 8105     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8106     # if (word-slice == '->') abort
 8107     (slice-equal? %ecx "->")   # => eax
 8108     3d/compare-eax-and 0/imm32/false
 8109     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8110     # if (word-slice == '}') abort
 8111     (slice-equal? %ecx "}")   # => eax
 8112     3d/compare-eax-and 0/imm32/false
 8113     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8114     # save function name
 8115     (slice-to-string Heap %ecx %edi)  # Function-name
 8116     # save function inouts
 8117     {
 8118 $populate-mu-function-signature:check-for-inout:
 8119       (next-mu-token *(ebp+8) %ecx)
 8120       (slice-empty? %ecx)  # => eax
 8121       3d/compare-eax-and 0/imm32/false
 8122       0f 85/jump-if-!= break/disp32
 8123       # if (word-slice == '->') break
 8124       (slice-equal? %ecx "->")   # => eax
 8125       3d/compare-eax-and 0/imm32/false
 8126       0f 85/jump-if-!= break/disp32
 8127       # if (word-slice == '{') abort
 8128       (slice-equal? %ecx "{")   # => eax
 8129       3d/compare-eax-and 0/imm32/false
 8130       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8131       # if (word-slice == '}') abort
 8132       (slice-equal? %ecx "}")   # => eax
 8133       3d/compare-eax-and 0/imm32/false
 8134       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8135       # v = parse-var-with-type(word-slice, first-line)
 8136       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8137       # assert(v->register == null)
 8138       # . eax: (addr var) = lookup(v)
 8139       (lookup *ebx *(ebx+4))  # => eax
 8140       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8141       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 8142       # v->block-depth is implicitly 0
 8143       #
 8144       # out->inouts = append(v, out->inouts)
 8145       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 8146       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 8147       #
 8148       e9/jump loop/disp32
 8149     }
 8150     # save function outputs
 8151     {
 8152 $populate-mu-function-signature:check-for-out:
 8153       (next-mu-token *(ebp+8) %ecx)
 8154       (slice-empty? %ecx)  # => eax
 8155       3d/compare-eax-and 0/imm32/false
 8156       0f 85/jump-if-!= break/disp32
 8157       # if (word-slice == '{') abort
 8158       (slice-equal? %ecx "{")   # => eax
 8159       3d/compare-eax-and 0/imm32/false
 8160       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8161       # if (word-slice == '->') abort
 8162       (slice-equal? %ecx "->")   # => eax
 8163       3d/compare-eax-and 0/imm32/false
 8164       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8165       # if (word-slice == '}') abort
 8166       (slice-equal? %ecx "}")   # => eax
 8167       3d/compare-eax-and 0/imm32/false
 8168       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 8169       # v = parse-var-with-type(word-slice, first-line)
 8170       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 8171       # assert(var->register != null)
 8172       # . eax: (addr var) = lookup(v)
 8173       (lookup *ebx *(ebx+4))  # => eax
 8174       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 8175       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 8176       # out->outputs = append(v, out->outputs)
 8177       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 8178       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 8179       #
 8180       e9/jump loop/disp32
 8181     }
 8182 $populate-mu-function-signature:done:
 8183     (check-no-tokens-left *(ebp+8))
 8184 $populate-mu-function-signature:end:
 8185     # . reclaim locals
 8186     81 0/subop/add %esp 0x10/imm32
 8187     # . restore registers
 8188     5f/pop-to-edi
 8189     5b/pop-to-ebx
 8190     5a/pop-to-edx
 8191     59/pop-to-ecx
 8192     58/pop-to-eax
 8193     # . epilogue
 8194     89/<- %esp 5/r32/ebp
 8195     5d/pop-to-ebp
 8196     c3/return
 8197 
 8198 $populate-mu-function-signature:error1:
 8199     # error("function signature not in form 'fn <name> {'")
 8200     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 8201     (flush *(ebp+0x10))
 8202     (rewind-stream *(ebp+8))
 8203     (write-stream-data *(ebp+0x10) *(ebp+8))
 8204     (write-buffered *(ebp+0x10) "'\n")
 8205     (flush *(ebp+0x10))
 8206     (stop *(ebp+0x14) 1)
 8207     # never gets here
 8208 
 8209 $populate-mu-function-signature:error2:
 8210     # error("fn " fn ": function inout '" var "' cannot be in a register")
 8211     (write-buffered *(ebp+0x10) "fn ")
 8212     50/push-eax
 8213     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8214     (write-buffered *(ebp+0x10) %eax)
 8215     58/pop-to-eax
 8216     (write-buffered *(ebp+0x10) ": function inout '")
 8217     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8218     (write-buffered *(ebp+0x10) %eax)
 8219     (write-buffered *(ebp+0x10) "' cannot be in a register")
 8220     (flush *(ebp+0x10))
 8221     (stop *(ebp+0x14) 1)
 8222     # never gets here
 8223 
 8224 $populate-mu-function-signature:error3:
 8225     # error("fn " fn ": function output '" var "' must be in a register")
 8226     (write-buffered *(ebp+0x10) "fn ")
 8227     50/push-eax
 8228     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 8229     (write-buffered *(ebp+0x10) %eax)
 8230     58/pop-to-eax
 8231     (write-buffered *(ebp+0x10) ": function output '")
 8232     (lookup *ebx *(ebx+4))  # => eax
 8233     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8234     (write-buffered *(ebp+0x10) %eax)
 8235     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 8236     (rewind-stream *(ebp+8))
 8237     (write-stream-data *(ebp+0x10) *(ebp+8))
 8238     (write-buffered *(ebp+0x10) "'\n")
 8239     (flush *(ebp+0x10))
 8240     (stop *(ebp+0x14) 1)
 8241     # never gets here
 8242 
 8243 test-function-header-with-arg:
 8244     # . prologue
 8245     55/push-ebp
 8246     89/<- %ebp 4/r32/esp
 8247     # setup
 8248     (clear-stream _test-input-stream)
 8249     (write _test-input-stream "foo n: int {\n")
 8250     # var result/ecx: function
 8251     2b/subtract *Function-size 4/r32/esp
 8252     89/<- %ecx 4/r32/esp
 8253     (zero-out %ecx *Function-size)
 8254     # var vars/ebx: (stack live-var 16)
 8255     81 5/subop/subtract %esp 0xc0/imm32
 8256     68/push 0xc0/imm32/size
 8257     68/push 0/imm32/top
 8258     89/<- %ebx 4/r32/esp
 8259     # convert
 8260     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8261     # check result->name
 8262     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8263     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 8264     # var v/edx: (addr var) = result->inouts->value
 8265     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8266     (lookup *eax *(eax+4))  # List-value List-value => eax
 8267     89/<- %edx 0/r32/eax
 8268     # check v->name
 8269     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 8270     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 8271     # check v->type
 8272     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 8273     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 8274     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 8275     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 8276     # . epilogue
 8277     89/<- %esp 5/r32/ebp
 8278     5d/pop-to-ebp
 8279     c3/return
 8280 
 8281 test-function-header-with-multiple-args:
 8282     # . prologue
 8283     55/push-ebp
 8284     89/<- %ebp 4/r32/esp
 8285     # setup
 8286     (clear-stream _test-input-stream)
 8287     (write _test-input-stream "foo a: int, b: int c: int {\n")
 8288     # result/ecx: function
 8289     2b/subtract *Function-size 4/r32/esp
 8290     89/<- %ecx 4/r32/esp
 8291     (zero-out %ecx *Function-size)
 8292     # var vars/ebx: (stack live-var 16)
 8293     81 5/subop/subtract %esp 0xc0/imm32
 8294     68/push 0xc0/imm32/size
 8295     68/push 0/imm32/top
 8296     89/<- %ebx 4/r32/esp
 8297     # convert
 8298     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8299     # check result->name
 8300     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8301     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 8302     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8303     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8304     89/<- %edx 0/r32/eax
 8305 $test-function-header-with-multiple-args:inout0:
 8306     # var v/ebx: (addr var) = lookup(inouts->value)
 8307     (lookup *edx *(edx+4))  # List-value List-value => eax
 8308     89/<- %ebx 0/r32/eax
 8309     # check v->name
 8310     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8311     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 8312     # check v->type
 8313     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8314     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 8315     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 8316     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 8317 $test-function-header-with-multiple-args:inout1:
 8318     # inouts = lookup(inouts->next)
 8319     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8320     89/<- %edx 0/r32/eax
 8321     # v = lookup(inouts->value)
 8322     (lookup *edx *(edx+4))  # List-value List-value => eax
 8323     89/<- %ebx 0/r32/eax
 8324     # check v->name
 8325     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8326     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 8327     # check v->type
 8328     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8329     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 8330     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 8331     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 8332 $test-function-header-with-multiple-args:inout2:
 8333     # inouts = lookup(inouts->next)
 8334     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8335     89/<- %edx 0/r32/eax
 8336     # v = lookup(inouts->value)
 8337     (lookup *edx *(edx+4))  # List-value List-value => eax
 8338     89/<- %ebx 0/r32/eax
 8339     # check v->name
 8340     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8341     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 8342     # check v->type
 8343     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8344     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 8345     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 8346     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 8347     # . epilogue
 8348     89/<- %esp 5/r32/ebp
 8349     5d/pop-to-ebp
 8350     c3/return
 8351 
 8352 test-function-header-with-multiple-args-and-outputs:
 8353     # . prologue
 8354     55/push-ebp
 8355     89/<- %ebp 4/r32/esp
 8356     # setup
 8357     (clear-stream _test-input-stream)
 8358     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 8359     # result/ecx: function
 8360     2b/subtract *Function-size 4/r32/esp
 8361     89/<- %ecx 4/r32/esp
 8362     (zero-out %ecx *Function-size)
 8363     # var vars/ebx: (stack live-var 16)
 8364     81 5/subop/subtract %esp 0xc0/imm32
 8365     68/push 0xc0/imm32/size
 8366     68/push 0/imm32/top
 8367     89/<- %ebx 4/r32/esp
 8368     # convert
 8369     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 8370     # check result->name
 8371     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8372     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 8373     # var inouts/edx: (addr list var) = lookup(result->inouts)
 8374     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8375     89/<- %edx 0/r32/eax
 8376 $test-function-header-with-multiple-args-and-outputs:inout0:
 8377     # var v/ebx: (addr var) = lookup(inouts->value)
 8378     (lookup *edx *(edx+4))  # List-value List-value => eax
 8379     89/<- %ebx 0/r32/eax
 8380     # check v->name
 8381     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8382     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 8383     # check v->type
 8384     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8385     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 8386     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 8387     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 8388 $test-function-header-with-multiple-args-and-outputs:inout1:
 8389     # inouts = lookup(inouts->next)
 8390     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8391     89/<- %edx 0/r32/eax
 8392     # v = lookup(inouts->value)
 8393     (lookup *edx *(edx+4))  # List-value List-value => eax
 8394     89/<- %ebx 0/r32/eax
 8395     # check v->name
 8396     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8397     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 8398     # check v->type
 8399     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8400     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 8401     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 8402     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 8403 $test-function-header-with-multiple-args-and-outputs:inout2:
 8404     # inouts = lookup(inouts->next)
 8405     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8406     89/<- %edx 0/r32/eax
 8407     # v = lookup(inouts->value)
 8408     (lookup *edx *(edx+4))  # List-value List-value => eax
 8409     89/<- %ebx 0/r32/eax
 8410     # check v->name
 8411     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8412     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 8413     # check v->type
 8414     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8415     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 8416     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 8417     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 8418 $test-function-header-with-multiple-args-and-outputs:out0:
 8419     # var outputs/edx: (addr list var) = lookup(result->outputs)
 8420     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8421     89/<- %edx 0/r32/eax
 8422     # v = lookup(outputs->value)
 8423     (lookup *edx *(edx+4))  # List-value List-value => eax
 8424     89/<- %ebx 0/r32/eax
 8425     # check v->name
 8426     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8427     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 8428     # check v->register
 8429     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8430     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 8431     # check v->type
 8432     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8433     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 8434     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 8435     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 8436 $test-function-header-with-multiple-args-and-outputs:out1:
 8437     # outputs = lookup(outputs->next)
 8438     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 8439     89/<- %edx 0/r32/eax
 8440     # v = lookup(inouts->value)
 8441     (lookup *edx *(edx+4))  # List-value List-value => eax
 8442     89/<- %ebx 0/r32/eax
 8443     # check v->name
 8444     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8445     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 8446     # check v->register
 8447     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8448     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 8449     # check v->type
 8450     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 8451     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 8452     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 8453     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 8454     # . epilogue
 8455     89/<- %esp 5/r32/ebp
 8456     5d/pop-to-ebp
 8457     c3/return
 8458 
 8459 # format for variables with types
 8460 #   x: int
 8461 #   x: int,
 8462 #   x/eax: int
 8463 #   x/eax: int,
 8464 # ignores at most one trailing comma
 8465 # WARNING: modifies name
 8466 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8467     # pseudocode:
 8468     #   var s: slice
 8469     #   if (!slice-ends-with(name, ":"))
 8470     #     abort
 8471     #   --name->end to skip ':'
 8472     #   next-token-from-slice(name->start, name->end, '/', s)
 8473     #   new-var-from-slice(s, out)
 8474     #   ## register
 8475     #   next-token-from-slice(s->end, name->end, '/', s)
 8476     #   if (!slice-empty?(s))
 8477     #     out->register = slice-to-string(s)
 8478     #   ## type
 8479     #   var type: (handle type-tree) = parse-type(first-line)
 8480     #   out->type = type
 8481     #
 8482     # . prologue
 8483     55/push-ebp
 8484     89/<- %ebp 4/r32/esp
 8485     # . save registers
 8486     50/push-eax
 8487     51/push-ecx
 8488     52/push-edx
 8489     53/push-ebx
 8490     56/push-esi
 8491     57/push-edi
 8492     # esi = name
 8493     8b/-> *(ebp+8) 6/r32/esi
 8494     # if (!slice-ends-with?(name, ":")) abort
 8495     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 8496     49/decrement-ecx
 8497     8a/copy-byte *ecx 1/r32/CL
 8498     81 4/subop/and %ecx 0xff/imm32
 8499     81 7/subop/compare %ecx 0x3a/imm32/colon
 8500     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 8501     # --name->end to skip ':'
 8502     ff 1/subop/decrement *(esi+4)
 8503     # var s/ecx: slice
 8504     68/push 0/imm32/end
 8505     68/push 0/imm32/start
 8506     89/<- %ecx 4/r32/esp
 8507 $parse-var-with-type:parse-name:
 8508     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 8509 $parse-var-with-type:create-var:
 8510     # new-var-from-slice(s, out)
 8511     (new-var-from-slice Heap %ecx *(ebp+0x10))
 8512     # save out->register
 8513 $parse-var-with-type:save-register:
 8514     # . var out-addr/edi: (addr var) = lookup(*out)
 8515     8b/-> *(ebp+0x10) 7/r32/edi
 8516     (lookup *edi *(edi+4))  # => eax
 8517     89/<- %edi 0/r32/eax
 8518     # . s = next-token(...)
 8519     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 8520     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 8521     {
 8522 $parse-var-with-type:write-register:
 8523       (slice-empty? %ecx)  # => eax
 8524       3d/compare-eax-and 0/imm32/false
 8525       75/jump-if-!= break/disp8
 8526       # out->register = slice-to-string(s)
 8527       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 8528       (slice-to-string Heap %ecx %eax)
 8529     }
 8530 $parse-var-with-type:save-type:
 8531     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 8532     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8533 $parse-var-with-type:end:
 8534     # . reclaim locals
 8535     81 0/subop/add %esp 8/imm32
 8536     # . restore registers
 8537     5f/pop-to-edi
 8538     5e/pop-to-esi
 8539     5b/pop-to-ebx
 8540     5a/pop-to-edx
 8541     59/pop-to-ecx
 8542     58/pop-to-eax
 8543     # . epilogue
 8544     89/<- %esp 5/r32/ebp
 8545     5d/pop-to-ebp
 8546     c3/return
 8547 
 8548 $parse-var-with-type:abort:
 8549     # error("var should have form 'name: type' in '" line "'\n")
 8550     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 8551     (flush *(ebp+0x14))
 8552     (rewind-stream *(ebp+0xc))
 8553     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 8554     (write-buffered *(ebp+0x14) "'\n")
 8555     (flush *(ebp+0x14))
 8556     (stop *(ebp+0x18) 1)
 8557     # never gets here
 8558 
 8559 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8560     # pseudocode:
 8561     #   var s: slice = next-mu-token(in)
 8562     #   assert s != ""
 8563     #   assert s != "->"
 8564     #   assert s != "{"
 8565     #   assert s != "}"
 8566     #   if s == ")"
 8567     #     return
 8568     #   out = allocate(Type-tree)
 8569     #   if s != "("
 8570     #     HACK: if s is an int, parse and return it
 8571     #     out->is-atom? = true
 8572     #     if (s[0] == "_")
 8573     #       out->value = type-parameter
 8574     #       out->parameter-name = slice-to-string(ad, s)
 8575     #     else
 8576     #       out->value = pos-or-insert-slice(Type-id, s)
 8577     #     return
 8578     #   out->left = parse-type(ad, in)
 8579     #   out->right = parse-type-tree(ad, in)
 8580     #
 8581     # . prologue
 8582     55/push-ebp
 8583     89/<- %ebp 4/r32/esp
 8584     # . save registers
 8585     50/push-eax
 8586     51/push-ecx
 8587     52/push-edx
 8588     # clear out
 8589     (zero-out *(ebp+0x10) *Handle-size)
 8590     # var s/ecx: slice
 8591     68/push 0/imm32
 8592     68/push 0/imm32
 8593     89/<- %ecx 4/r32/esp
 8594     # s = next-mu-token(in)
 8595     (next-mu-token *(ebp+0xc) %ecx)
 8596 #?     (write-buffered Stderr "tok: ")
 8597 #?     (write-slice-buffered Stderr %ecx)
 8598 #?     (write-buffered Stderr "$\n")
 8599 #?     (flush Stderr)
 8600     # assert s != ""
 8601     (slice-equal? %ecx "")  # => eax
 8602     3d/compare-eax-and 0/imm32/false
 8603     0f 85/jump-if-!= $parse-type:abort/disp32
 8604     # assert s != "{"
 8605     (slice-equal? %ecx "{")  # => eax
 8606     3d/compare-eax-and 0/imm32/false
 8607     0f 85/jump-if-!= $parse-type:abort/disp32
 8608     # assert s != "}"
 8609     (slice-equal? %ecx "}")  # => eax
 8610     3d/compare-eax-and 0/imm32/false
 8611     0f 85/jump-if-!= $parse-type:abort/disp32
 8612     # assert s != "->"
 8613     (slice-equal? %ecx "->")  # => eax
 8614     3d/compare-eax-and 0/imm32/false
 8615     0f 85/jump-if-!= $parse-type:abort/disp32
 8616     # if (s == ")") return
 8617     (slice-equal? %ecx ")")  # => eax
 8618     3d/compare-eax-and 0/imm32/false
 8619     0f 85/jump-if-!= $parse-type:end/disp32
 8620     # out = new tree
 8621     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 8622     # var out-addr/edx: (addr type-tree) = lookup(*out)
 8623     8b/-> *(ebp+0x10) 2/r32/edx
 8624     (lookup *edx *(edx+4))  # => eax
 8625     89/<- %edx 0/r32/eax
 8626     {
 8627       # if (s != "(") break
 8628       (slice-equal? %ecx "(")  # => eax
 8629       3d/compare-eax-and 0/imm32/false
 8630       0f 85/jump-if-!= break/disp32
 8631       # if s is a number, store it in the type's size field
 8632       {
 8633 $parse-type:check-for-int:
 8634         # var tmp/eax: byte = *s->slice
 8635         8b/-> *ecx 0/r32/eax
 8636         8a/copy-byte *eax 0/r32/AL
 8637         81 4/subop/and %eax 0xff/imm32
 8638         # TODO: raise an error on `var x: (array int a)`
 8639         (is-decimal-digit? %eax)  # => eax
 8640         3d/compare-eax-and 0/imm32/false
 8641         74/jump-if-= break/disp8
 8642         #
 8643         (is-hex-int? %ecx)  # => eax
 8644         3d/compare-eax-and 0/imm32/false
 8645         74/jump-if-= break/disp8
 8646 $parse-type:int:
 8647         (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
 8648         (parse-hex-int-from-slice %ecx)  # => eax
 8649         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 8650         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 8651         e9/jump $parse-type:end/disp32
 8652       }
 8653 $parse-type:atom:
 8654       # out->is-atom? = true
 8655       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 8656       {
 8657 $parse-type:check-for-type-parameter:
 8658         # var tmp/eax: byte = *s->slice
 8659         8b/-> *ecx 0/r32/eax
 8660         8a/copy-byte *eax 0/r32/AL
 8661         81 4/subop/and %eax 0xff/imm32
 8662         # if (tmp != '_') break
 8663         3d/compare-eax-and 0x5f/imm32/_
 8664         75/jump-if-!= break/disp8
 8665 $parse-type:type-parameter:
 8666         # out->value = type-parameter
 8667         c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
 8668         # out->parameter-name = slice-to-string(ad, s)
 8669         8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
 8670         (slice-to-string *(ebp+8) %ecx %eax)
 8671         e9/jump $parse-type:end/disp32
 8672       }
 8673 $parse-type:non-type-parameter:
 8674       # out->value = pos-or-insert-slice(Type-id, s)
 8675       (pos-or-insert-slice Type-id %ecx)  # => eax
 8676       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 8677       e9/jump $parse-type:end/disp32
 8678     }
 8679 $parse-type:non-atom:
 8680     # otherwise s == "("
 8681     # out->left = parse-type(ad, in)
 8682     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 8683     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8684     # out->right = parse-type-tree(ad, in)
 8685     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 8686     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8687 $parse-type:end:
 8688     # . reclaim locals
 8689     81 0/subop/add %esp 8/imm32
 8690     # . restore registers
 8691     5a/pop-to-edx
 8692     59/pop-to-ecx
 8693     58/pop-to-eax
 8694     # . epilogue
 8695     89/<- %esp 5/r32/ebp
 8696     5d/pop-to-ebp
 8697     c3/return
 8698 
 8699 $parse-type:abort:
 8700     # error("unexpected token when parsing type: '" s "'\n")
 8701     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 8702     (write-slice-buffered *(ebp+0x14) %ecx)
 8703     (write-buffered *(ebp+0x14) "'\n")
 8704     (flush *(ebp+0x14))
 8705     (stop *(ebp+0x18) 1)
 8706     # never gets here
 8707 
 8708 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 8709     # pseudocode:
 8710     #   var tmp: (handle type-tree) = parse-type(ad, in)
 8711     #   if tmp == 0
 8712     #     return 0
 8713     #   out = allocate(Type-tree)
 8714     #   out->left = tmp
 8715     #   out->right = parse-type-tree(ad, in)
 8716     #
 8717     # . prologue
 8718     55/push-ebp
 8719     89/<- %ebp 4/r32/esp
 8720     # . save registers
 8721     50/push-eax
 8722     51/push-ecx
 8723     52/push-edx
 8724     #
 8725     (zero-out *(ebp+0x10) *Handle-size)
 8726     # var tmp/ecx: (handle type-tree)
 8727     68/push 0/imm32
 8728     68/push 0/imm32
 8729     89/<- %ecx 4/r32/esp
 8730     # tmp = parse-type(ad, in)
 8731     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 8732     # if (tmp == 0) return
 8733     81 7/subop/compare *ecx 0/imm32
 8734     74/jump-if-= $parse-type-tree:end/disp8
 8735     # out = new tree
 8736     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 8737     # var out-addr/edx: (addr tree) = lookup(*out)
 8738     8b/-> *(ebp+0x10) 2/r32/edx
 8739     (lookup *edx *(edx+4))  # => eax
 8740     89/<- %edx 0/r32/eax
 8741     # out->left = tmp
 8742     8b/-> *ecx 0/r32/eax
 8743     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 8744     8b/-> *(ecx+4) 0/r32/eax
 8745     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 8746     # out->right = parse-type-tree(ad, in)
 8747     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 8748     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 8749 $parse-type-tree:end:
 8750     # . reclaim locals
 8751     81 0/subop/add %esp 8/imm32
 8752     # . restore registers
 8753     5a/pop-to-edx
 8754     59/pop-to-ecx
 8755     58/pop-to-eax
 8756     # . epilogue
 8757     89/<- %esp 5/r32/ebp
 8758     5d/pop-to-ebp
 8759     c3/return
 8760 
 8761 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 8762     # pseudocode:
 8763     # start:
 8764     #   skip-chars-matching-whitespace(in)
 8765     #   if in->read >= in->write              # end of in
 8766     #     out = {0, 0}
 8767     #     return
 8768     #   out->start = &in->data[in->read]
 8769     #   var curr-byte/eax: byte = in->data[in->read]
 8770     #   if curr->byte == ','                  # comment token
 8771     #     ++in->read
 8772     #     goto start
 8773     #   if curr-byte == '#'                   # comment
 8774     #     goto done                             # treat as eof
 8775     #   if curr-byte == '"'                   # string literal
 8776     #     skip-string(in)
 8777     #     goto done                           # no metadata
 8778     #   if curr-byte == '('
 8779     #     ++in->read
 8780     #     goto done
 8781     #   if curr-byte == ')'
 8782     #     ++in->read
 8783     #     goto done
 8784     #   # read a word
 8785     #   while true
 8786     #     if in->read >= in->write
 8787     #       break
 8788     #     curr-byte = in->data[in->read]
 8789     #     if curr-byte == ' '
 8790     #       break
 8791     #     if curr-byte == '\r'
 8792     #       break
 8793     #     if curr-byte == '\n'
 8794     #       break
 8795     #     if curr-byte == '('
 8796     #       break
 8797     #     if curr-byte == ')'
 8798     #       break
 8799     #     if curr-byte == ','
 8800     #       break
 8801     #     ++in->read
 8802     # done:
 8803     #   out->end = &in->data[in->read]
 8804     #
 8805     # . prologue
 8806     55/push-ebp
 8807     89/<- %ebp 4/r32/esp
 8808     # . save registers
 8809     50/push-eax
 8810     51/push-ecx
 8811     56/push-esi
 8812     57/push-edi
 8813     # esi = in
 8814     8b/-> *(ebp+8) 6/r32/esi
 8815     # edi = out
 8816     8b/-> *(ebp+0xc) 7/r32/edi
 8817 $next-mu-token:start:
 8818     (skip-chars-matching-whitespace %esi)
 8819 $next-mu-token:check0:
 8820     # if (in->read >= in->write) return out = {0, 0}
 8821     # . ecx = in->read
 8822     8b/-> *(esi+4) 1/r32/ecx
 8823     # . if (ecx >= in->write) return out = {0, 0}
 8824     3b/compare<- *esi 1/r32/ecx
 8825     c7 0/subop/copy *edi 0/imm32
 8826     c7 0/subop/copy *(edi+4) 0/imm32
 8827     0f 8d/jump-if->= $next-mu-token:end/disp32
 8828     # out->start = &in->data[in->read]
 8829     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 8830     89/<- *edi 0/r32/eax
 8831     # var curr-byte/eax: byte = in->data[in->read]
 8832     31/xor-with %eax 0/r32/eax
 8833     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 8834     {
 8835 $next-mu-token:check-for-comma:
 8836       # if (curr-byte != ',') break
 8837       3d/compare-eax-and 0x2c/imm32/comma
 8838       75/jump-if-!= break/disp8
 8839       # ++in->read
 8840       ff 0/subop/increment *(esi+4)
 8841       # restart
 8842       e9/jump $next-mu-token:start/disp32
 8843     }
 8844     {
 8845 $next-mu-token:check-for-comment:
 8846       # if (curr-byte != '#') break
 8847       3d/compare-eax-and 0x23/imm32/pound
 8848       75/jump-if-!= break/disp8
 8849       # return eof
 8850       e9/jump $next-mu-token:done/disp32
 8851     }
 8852     {
 8853 $next-mu-token:check-for-string-literal:
 8854       # if (curr-byte != '"') break
 8855       3d/compare-eax-and 0x22/imm32/dquote
 8856       75/jump-if-!= break/disp8
 8857       (skip-string %esi)
 8858       # return
 8859       e9/jump $next-mu-token:done/disp32
 8860     }
 8861     {
 8862 $next-mu-token:check-for-open-paren:
 8863       # if (curr-byte != '(') break
 8864       3d/compare-eax-and 0x28/imm32/open-paren
 8865       75/jump-if-!= break/disp8
 8866       # ++in->read
 8867       ff 0/subop/increment *(esi+4)
 8868       # return
 8869       e9/jump $next-mu-token:done/disp32
 8870     }
 8871     {
 8872 $next-mu-token:check-for-close-paren:
 8873       # if (curr-byte != ')') break
 8874       3d/compare-eax-and 0x29/imm32/close-paren
 8875       75/jump-if-!= break/disp8
 8876       # ++in->read
 8877       ff 0/subop/increment *(esi+4)
 8878       # return
 8879       e9/jump $next-mu-token:done/disp32
 8880     }
 8881     {
 8882 $next-mu-token:regular-word-without-metadata:
 8883       # if (in->read >= in->write) break
 8884       # . ecx = in->read
 8885       8b/-> *(esi+4) 1/r32/ecx
 8886       # . if (ecx >= in->write) break
 8887       3b/compare<- *esi 1/r32/ecx
 8888       7d/jump-if->= break/disp8
 8889       # var c/eax: byte = in->data[in->read]
 8890       31/xor-with %eax 0/r32/eax
 8891       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 8892       # if (c == ' ') break
 8893       3d/compare-eax-and 0x20/imm32/space
 8894       74/jump-if-= break/disp8
 8895       # if (c == '\r') break
 8896       3d/compare-eax-and 0xd/imm32/carriage-return
 8897       74/jump-if-= break/disp8
 8898       # if (c == '\n') break
 8899       3d/compare-eax-and 0xa/imm32/newline
 8900       74/jump-if-= break/disp8
 8901       # if (c == '(') break
 8902       3d/compare-eax-and 0x28/imm32/open-paren
 8903       0f 84/jump-if-= break/disp32
 8904       # if (c == ')') break
 8905       3d/compare-eax-and 0x29/imm32/close-paren
 8906       0f 84/jump-if-= break/disp32
 8907       # if (c == ',') break
 8908       3d/compare-eax-and 0x2c/imm32/comma
 8909       0f 84/jump-if-= break/disp32
 8910       # ++in->read
 8911       ff 0/subop/increment *(esi+4)
 8912       #
 8913       e9/jump loop/disp32
 8914     }
 8915 $next-mu-token:done:
 8916     # out->end = &in->data[in->read]
 8917     8b/-> *(esi+4) 1/r32/ecx
 8918     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 8919     89/<- *(edi+4) 0/r32/eax
 8920 $next-mu-token:end:
 8921     # . restore registers
 8922     5f/pop-to-edi
 8923     5e/pop-to-esi
 8924     59/pop-to-ecx
 8925     58/pop-to-eax
 8926     # . epilogue
 8927     89/<- %esp 5/r32/ebp
 8928     5d/pop-to-ebp
 8929     c3/return
 8930 
 8931 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 8932     # . prologue
 8933     55/push-ebp
 8934     89/<- %ebp 4/r32/esp
 8935     # if (pos-slice(arr, s) != -1) return it
 8936     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 8937     3d/compare-eax-and -1/imm32
 8938     75/jump-if-!= $pos-or-insert-slice:end/disp8
 8939 $pos-or-insert-slice:insert:
 8940     # var s2/eax: (handle array byte)
 8941     68/push 0/imm32
 8942     68/push 0/imm32
 8943     89/<- %eax 4/r32/esp
 8944     (slice-to-string Heap *(ebp+0xc) %eax)
 8945     # throw away alloc-id
 8946     (lookup *eax *(eax+4))  # => eax
 8947     (write-int *(ebp+8) %eax)
 8948     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 8949 $pos-or-insert-slice:end:
 8950     # . reclaim locals
 8951     81 0/subop/add %esp 8/imm32
 8952     # . epilogue
 8953     89/<- %esp 5/r32/ebp
 8954     5d/pop-to-ebp
 8955     c3/return
 8956 
 8957 # return the index in an array of strings matching 's', -1 if not found
 8958 # index is denominated in elements, not bytes
 8959 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 8960     # . prologue
 8961     55/push-ebp
 8962     89/<- %ebp 4/r32/esp
 8963     # . save registers
 8964     51/push-ecx
 8965     52/push-edx
 8966     53/push-ebx
 8967     56/push-esi
 8968 #?     (write-buffered Stderr "pos-slice: ")
 8969 #?     (write-slice-buffered Stderr *(ebp+0xc))
 8970 #?     (write-buffered Stderr "\n")
 8971 #?     (flush Stderr)
 8972     # esi = arr
 8973     8b/-> *(ebp+8) 6/r32/esi
 8974     # var index/ecx: int = 0
 8975     b9/copy-to-ecx 0/imm32
 8976     # var curr/edx: (addr (addr array byte)) = arr->data
 8977     8d/copy-address *(esi+0xc) 2/r32/edx
 8978     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 8979     8b/-> *esi 3/r32/ebx
 8980     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 8981     {
 8982 #?       (write-buffered Stderr "  ")
 8983 #?       (write-int32-hex-buffered Stderr %ecx)
 8984 #?       (write-buffered Stderr "\n")
 8985 #?       (flush Stderr)
 8986       # if (curr >= max) return -1
 8987       39/compare %edx 3/r32/ebx
 8988       b8/copy-to-eax -1/imm32
 8989       73/jump-if-addr>= $pos-slice:end/disp8
 8990       # if (slice-equal?(s, *curr)) break
 8991       (slice-equal? *(ebp+0xc) *edx)  # => eax
 8992       3d/compare-eax-and 0/imm32/false
 8993       75/jump-if-!= break/disp8
 8994       # ++index
 8995       41/increment-ecx
 8996       # curr += 4
 8997       81 0/subop/add %edx 4/imm32
 8998       #
 8999       eb/jump loop/disp8
 9000     }
 9001     # return index
 9002     89/<- %eax 1/r32/ecx
 9003 $pos-slice:end:
 9004 #?     (write-buffered Stderr "=> ")
 9005 #?     (write-int32-hex-buffered Stderr %eax)
 9006 #?     (write-buffered Stderr "\n")
 9007     # . restore registers
 9008     5e/pop-to-esi
 9009     5b/pop-to-ebx
 9010     5a/pop-to-edx
 9011     59/pop-to-ecx
 9012     # . epilogue
 9013     89/<- %esp 5/r32/ebp
 9014     5d/pop-to-ebp
 9015     c3/return
 9016 
 9017 test-parse-var-with-type:
 9018     # . prologue
 9019     55/push-ebp
 9020     89/<- %ebp 4/r32/esp
 9021     # (eax..ecx) = "x:"
 9022     b8/copy-to-eax "x:"/imm32
 9023     8b/-> *eax 1/r32/ecx
 9024     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9025     05/add-to-eax 4/imm32
 9026     # var slice/ecx: slice = {eax, ecx}
 9027     51/push-ecx
 9028     50/push-eax
 9029     89/<- %ecx 4/r32/esp
 9030     # _test-input-stream contains "int"
 9031     (clear-stream _test-input-stream)
 9032     (write _test-input-stream "int")
 9033     # var v/edx: (handle var)
 9034     68/push 0/imm32
 9035     68/push 0/imm32
 9036     89/<- %edx 4/r32/esp
 9037     #
 9038     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9039     # var v-addr/edx: (addr var) = lookup(v)
 9040     (lookup *edx *(edx+4))  # => eax
 9041     89/<- %edx 0/r32/eax
 9042     # check v-addr->name
 9043     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9044     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 9045     # check v-addr->type
 9046     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9047     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 9048     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 9049     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 9050     # . epilogue
 9051     89/<- %esp 5/r32/ebp
 9052     5d/pop-to-ebp
 9053     c3/return
 9054 
 9055 test-parse-var-with-type-and-register:
 9056     # . prologue
 9057     55/push-ebp
 9058     89/<- %ebp 4/r32/esp
 9059     # (eax..ecx) = "x/eax:"
 9060     b8/copy-to-eax "x/eax:"/imm32
 9061     8b/-> *eax 1/r32/ecx
 9062     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9063     05/add-to-eax 4/imm32
 9064     # var slice/ecx: slice = {eax, ecx}
 9065     51/push-ecx
 9066     50/push-eax
 9067     89/<- %ecx 4/r32/esp
 9068     # _test-input-stream contains "int"
 9069     (clear-stream _test-input-stream)
 9070     (write _test-input-stream "int")
 9071     # var v/edx: (handle var)
 9072     68/push 0/imm32
 9073     68/push 0/imm32
 9074     89/<- %edx 4/r32/esp
 9075     #
 9076     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9077     # var v-addr/edx: (addr var) = lookup(v)
 9078     (lookup *edx *(edx+4))  # => eax
 9079     89/<- %edx 0/r32/eax
 9080     # check v-addr->name
 9081     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9082     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 9083     # check v-addr->register
 9084     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9085     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 9086     # check v-addr->type
 9087     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9088     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 9089     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 9090     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 9091     # . epilogue
 9092     89/<- %esp 5/r32/ebp
 9093     5d/pop-to-ebp
 9094     c3/return
 9095 
 9096 test-parse-var-with-trailing-characters:
 9097     # . prologue
 9098     55/push-ebp
 9099     89/<- %ebp 4/r32/esp
 9100     # (eax..ecx) = "x:"
 9101     b8/copy-to-eax "x:"/imm32
 9102     8b/-> *eax 1/r32/ecx
 9103     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9104     05/add-to-eax 4/imm32
 9105     # var slice/ecx: slice = {eax, ecx}
 9106     51/push-ecx
 9107     50/push-eax
 9108     89/<- %ecx 4/r32/esp
 9109     # _test-input-stream contains "int,"
 9110     (clear-stream _test-input-stream)
 9111     (write _test-input-stream "int,")
 9112     # var v/edx: (handle var)
 9113     68/push 0/imm32
 9114     68/push 0/imm32
 9115     89/<- %edx 4/r32/esp
 9116     #
 9117     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9118     # var v-addr/edx: (addr var) = lookup(v)
 9119     (lookup *edx *(edx+4))  # => eax
 9120     89/<- %edx 0/r32/eax
 9121     # check v-addr->name
 9122     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9123     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 9124     # check v-addr->register
 9125     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 9126     # check v-addr->type
 9127     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9128     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 9129     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 9130     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 9131     # . epilogue
 9132     89/<- %esp 5/r32/ebp
 9133     5d/pop-to-ebp
 9134     c3/return
 9135 
 9136 test-parse-var-with-register-and-trailing-characters:
 9137     # . prologue
 9138     55/push-ebp
 9139     89/<- %ebp 4/r32/esp
 9140     # (eax..ecx) = "x/eax:"
 9141     b8/copy-to-eax "x/eax:"/imm32
 9142     8b/-> *eax 1/r32/ecx
 9143     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9144     05/add-to-eax 4/imm32
 9145     # var slice/ecx: slice = {eax, ecx}
 9146     51/push-ecx
 9147     50/push-eax
 9148     89/<- %ecx 4/r32/esp
 9149     # _test-input-stream contains "int,"
 9150     (clear-stream _test-input-stream)
 9151     (write _test-input-stream "int,")
 9152     # var v/edx: (handle var)
 9153     68/push 0/imm32
 9154     68/push 0/imm32
 9155     89/<- %edx 4/r32/esp
 9156     #
 9157     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9158     # var v-addr/edx: (addr var) = lookup(v)
 9159     (lookup *edx *(edx+4))  # => eax
 9160     89/<- %edx 0/r32/eax
 9161     # check v-addr->name
 9162     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9163     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 9164     # check v-addr->register
 9165     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9166     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 9167     # check v-addr->type
 9168     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9169     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 9170     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 9171     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 9172     # . epilogue
 9173     89/<- %esp 5/r32/ebp
 9174     5d/pop-to-ebp
 9175     c3/return
 9176 
 9177 test-parse-var-with-compound-type:
 9178     # . prologue
 9179     55/push-ebp
 9180     89/<- %ebp 4/r32/esp
 9181     # (eax..ecx) = "x:"
 9182     b8/copy-to-eax "x:"/imm32
 9183     8b/-> *eax 1/r32/ecx
 9184     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9185     05/add-to-eax 4/imm32
 9186     # var slice/ecx: slice = {eax, ecx}
 9187     51/push-ecx
 9188     50/push-eax
 9189     89/<- %ecx 4/r32/esp
 9190     # _test-input-stream contains "(addr int)"
 9191     (clear-stream _test-input-stream)
 9192     (write _test-input-stream "(addr int)")
 9193     # var v/edx: (handle var)
 9194     68/push 0/imm32
 9195     68/push 0/imm32
 9196     89/<- %edx 4/r32/esp
 9197     #
 9198     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 9199     # var v-addr/edx: (addr var) = lookup(v)
 9200     (lookup *edx *(edx+4))  # => eax
 9201     89/<- %edx 0/r32/eax
 9202     # check v-addr->name
 9203     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9204     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 9205     # check v-addr->register
 9206     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 9207     # - check v-addr->type
 9208     # var type/edx: (addr type-tree) = var->type
 9209     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9210     89/<- %edx 0/r32/eax
 9211     # type is a non-atom
 9212     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 9213     # type->left == atom(addr)
 9214     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 9215     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 9216     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 9217     # type->right->left == atom(int)
 9218     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 9219     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 9220     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 9221     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 9222     # type->right->right == null
 9223     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 9224     # . epilogue
 9225     89/<- %esp 5/r32/ebp
 9226     5d/pop-to-ebp
 9227     c3/return
 9228 
 9229 # identifier starts with a letter or '$' or '_'
 9230 # no constraints at the moment on later letters
 9231 # all we really want to do so far is exclude '{', '}' and '->'
 9232 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 9233     # . prologue
 9234     55/push-ebp
 9235     89/<- %ebp 4/r32/esp
 9236     # if (slice-empty?(in)) return false
 9237     (slice-empty? *(ebp+8))  # => eax
 9238     3d/compare-eax-and 0/imm32/false
 9239     75/jump-if-!= $is-identifier?:false/disp8
 9240     # var c/eax: byte = *in->start
 9241     8b/-> *(ebp+8) 0/r32/eax
 9242     8b/-> *eax 0/r32/eax
 9243     8a/copy-byte *eax 0/r32/AL
 9244     81 4/subop/and %eax 0xff/imm32
 9245     # if (c == '$') return true
 9246     3d/compare-eax-and 0x24/imm32/$
 9247     74/jump-if-= $is-identifier?:true/disp8
 9248     # if (c == '_') return true
 9249     3d/compare-eax-and 0x5f/imm32/_
 9250     74/jump-if-= $is-identifier?:true/disp8
 9251     # drop case
 9252     25/and-eax-with 0x5f/imm32
 9253     # if (c < 'A') return false
 9254     3d/compare-eax-and 0x41/imm32/A
 9255     7c/jump-if-< $is-identifier?:false/disp8
 9256     # if (c > 'Z') return false
 9257     3d/compare-eax-and 0x5a/imm32/Z
 9258     7f/jump-if-> $is-identifier?:false/disp8
 9259     # otherwise return true
 9260 $is-identifier?:true:
 9261     b8/copy-to-eax 1/imm32/true
 9262     eb/jump $is-identifier?:end/disp8
 9263 $is-identifier?:false:
 9264     b8/copy-to-eax 0/imm32/false
 9265 $is-identifier?:end:
 9266     # . epilogue
 9267     89/<- %esp 5/r32/ebp
 9268     5d/pop-to-ebp
 9269     c3/return
 9270 
 9271 test-is-identifier-dollar:
 9272     # . prologue
 9273     55/push-ebp
 9274     89/<- %ebp 4/r32/esp
 9275     # (eax..ecx) = "$a"
 9276     b8/copy-to-eax "$a"/imm32
 9277     8b/-> *eax 1/r32/ecx
 9278     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9279     05/add-to-eax 4/imm32
 9280     # var slice/ecx: slice = {eax, ecx}
 9281     51/push-ecx
 9282     50/push-eax
 9283     89/<- %ecx 4/r32/esp
 9284     #
 9285     (is-identifier? %ecx)
 9286     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 9287     # . epilogue
 9288     89/<- %esp 5/r32/ebp
 9289     5d/pop-to-ebp
 9290     c3/return
 9291 
 9292 test-is-identifier-underscore:
 9293     # . prologue
 9294     55/push-ebp
 9295     89/<- %ebp 4/r32/esp
 9296     # (eax..ecx) = "_a"
 9297     b8/copy-to-eax "_a"/imm32
 9298     8b/-> *eax 1/r32/ecx
 9299     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9300     05/add-to-eax 4/imm32
 9301     # var slice/ecx: slice = {eax, ecx}
 9302     51/push-ecx
 9303     50/push-eax
 9304     89/<- %ecx 4/r32/esp
 9305     #
 9306     (is-identifier? %ecx)
 9307     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 9308     # . epilogue
 9309     89/<- %esp 5/r32/ebp
 9310     5d/pop-to-ebp
 9311     c3/return
 9312 
 9313 test-is-identifier-a:
 9314     # . prologue
 9315     55/push-ebp
 9316     89/<- %ebp 4/r32/esp
 9317     # (eax..ecx) = "a$"
 9318     b8/copy-to-eax "a$"/imm32
 9319     8b/-> *eax 1/r32/ecx
 9320     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9321     05/add-to-eax 4/imm32
 9322     # var slice/ecx: slice = {eax, ecx}
 9323     51/push-ecx
 9324     50/push-eax
 9325     89/<- %ecx 4/r32/esp
 9326     #
 9327     (is-identifier? %ecx)
 9328     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 9329     # . epilogue
 9330     89/<- %esp 5/r32/ebp
 9331     5d/pop-to-ebp
 9332     c3/return
 9333 
 9334 test-is-identifier-z:
 9335     # . prologue
 9336     55/push-ebp
 9337     89/<- %ebp 4/r32/esp
 9338     # (eax..ecx) = "z$"
 9339     b8/copy-to-eax "z$"/imm32
 9340     8b/-> *eax 1/r32/ecx
 9341     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9342     05/add-to-eax 4/imm32
 9343     # var slice/ecx: slice = {eax, ecx}
 9344     51/push-ecx
 9345     50/push-eax
 9346     89/<- %ecx 4/r32/esp
 9347     #
 9348     (is-identifier? %ecx)
 9349     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 9350     # . epilogue
 9351     89/<- %esp 5/r32/ebp
 9352     5d/pop-to-ebp
 9353     c3/return
 9354 
 9355 test-is-identifier-A:
 9356     # . prologue
 9357     55/push-ebp
 9358     89/<- %ebp 4/r32/esp
 9359     # (eax..ecx) = "A$"
 9360     b8/copy-to-eax "A$"/imm32
 9361     8b/-> *eax 1/r32/ecx
 9362     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9363     05/add-to-eax 4/imm32
 9364     # var slice/ecx: slice = {eax, ecx}
 9365     51/push-ecx
 9366     50/push-eax
 9367     89/<- %ecx 4/r32/esp
 9368     #
 9369     (is-identifier? %ecx)
 9370     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 9371     # . epilogue
 9372     89/<- %esp 5/r32/ebp
 9373     5d/pop-to-ebp
 9374     c3/return
 9375 
 9376 test-is-identifier-Z:
 9377     # . prologue
 9378     55/push-ebp
 9379     89/<- %ebp 4/r32/esp
 9380     # (eax..ecx) = "Z$"
 9381     b8/copy-to-eax "Z$"/imm32
 9382     8b/-> *eax 1/r32/ecx
 9383     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9384     05/add-to-eax 4/imm32
 9385     # var slice/ecx: slice = {eax, ecx}
 9386     51/push-ecx
 9387     50/push-eax
 9388     89/<- %ecx 4/r32/esp
 9389     #
 9390     (is-identifier? %ecx)
 9391     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 9392     # . epilogue
 9393     89/<- %esp 5/r32/ebp
 9394     5d/pop-to-ebp
 9395     c3/return
 9396 
 9397 test-is-identifier-at:
 9398     # character before 'A' is invalid
 9399     # . prologue
 9400     55/push-ebp
 9401     89/<- %ebp 4/r32/esp
 9402     # (eax..ecx) = "@a"
 9403     b8/copy-to-eax "@a"/imm32
 9404     8b/-> *eax 1/r32/ecx
 9405     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9406     05/add-to-eax 4/imm32
 9407     # var slice/ecx: slice = {eax, ecx}
 9408     51/push-ecx
 9409     50/push-eax
 9410     89/<- %ecx 4/r32/esp
 9411     #
 9412     (is-identifier? %ecx)
 9413     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9414     # . epilogue
 9415     89/<- %esp 5/r32/ebp
 9416     5d/pop-to-ebp
 9417     c3/return
 9418 
 9419 test-is-identifier-square-bracket:
 9420     # character after 'Z' is invalid
 9421     # . prologue
 9422     55/push-ebp
 9423     89/<- %ebp 4/r32/esp
 9424     # (eax..ecx) = "[a"
 9425     b8/copy-to-eax "[a"/imm32
 9426     8b/-> *eax 1/r32/ecx
 9427     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9428     05/add-to-eax 4/imm32
 9429     # var slice/ecx: slice = {eax, ecx}
 9430     51/push-ecx
 9431     50/push-eax
 9432     89/<- %ecx 4/r32/esp
 9433     #
 9434     (is-identifier? %ecx)
 9435     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 9436     # . epilogue
 9437     89/<- %esp 5/r32/ebp
 9438     5d/pop-to-ebp
 9439     c3/return
 9440 
 9441 test-is-identifier-backtick:
 9442     # character before 'a' is invalid
 9443     # . prologue
 9444     55/push-ebp
 9445     89/<- %ebp 4/r32/esp
 9446     # (eax..ecx) = "`a"
 9447     b8/copy-to-eax "`a"/imm32
 9448     8b/-> *eax 1/r32/ecx
 9449     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9450     05/add-to-eax 4/imm32
 9451     # var slice/ecx: slice = {eax, ecx}
 9452     51/push-ecx
 9453     50/push-eax
 9454     89/<- %ecx 4/r32/esp
 9455     #
 9456     (is-identifier? %ecx)
 9457     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 9458     # . epilogue
 9459     89/<- %esp 5/r32/ebp
 9460     5d/pop-to-ebp
 9461     c3/return
 9462 
 9463 test-is-identifier-curly-brace-open:
 9464     # character after 'z' is invalid; also used for blocks
 9465     # . prologue
 9466     55/push-ebp
 9467     89/<- %ebp 4/r32/esp
 9468     # (eax..ecx) = "{a"
 9469     b8/copy-to-eax "{a"/imm32
 9470     8b/-> *eax 1/r32/ecx
 9471     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9472     05/add-to-eax 4/imm32
 9473     # var slice/ecx: slice = {eax, ecx}
 9474     51/push-ecx
 9475     50/push-eax
 9476     89/<- %ecx 4/r32/esp
 9477     #
 9478     (is-identifier? %ecx)
 9479     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 9480     # . epilogue
 9481     89/<- %esp 5/r32/ebp
 9482     5d/pop-to-ebp
 9483     c3/return
 9484 
 9485 test-is-identifier-curly-brace-close:
 9486     # . prologue
 9487     55/push-ebp
 9488     89/<- %ebp 4/r32/esp
 9489     # (eax..ecx) = "}a"
 9490     b8/copy-to-eax "}a"/imm32
 9491     8b/-> *eax 1/r32/ecx
 9492     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9493     05/add-to-eax 4/imm32
 9494     # var slice/ecx: slice = {eax, ecx}
 9495     51/push-ecx
 9496     50/push-eax
 9497     89/<- %ecx 4/r32/esp
 9498     #
 9499     (is-identifier? %ecx)
 9500     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 9501     # . epilogue
 9502     89/<- %esp 5/r32/ebp
 9503     5d/pop-to-ebp
 9504     c3/return
 9505 
 9506 test-is-identifier-hyphen:
 9507     # disallow leading '-' since '->' has special meaning
 9508     # . prologue
 9509     55/push-ebp
 9510     89/<- %ebp 4/r32/esp
 9511     # (eax..ecx) = "-a"
 9512     b8/copy-to-eax "-a"/imm32
 9513     8b/-> *eax 1/r32/ecx
 9514     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 9515     05/add-to-eax 4/imm32
 9516     # var slice/ecx: slice = {eax, ecx}
 9517     51/push-ecx
 9518     50/push-eax
 9519     89/<- %ecx 4/r32/esp
 9520     #
 9521     (is-identifier? %ecx)
 9522     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 9523     # . epilogue
 9524     89/<- %esp 5/r32/ebp
 9525     5d/pop-to-ebp
 9526     c3/return
 9527 
 9528 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9529     # . prologue
 9530     55/push-ebp
 9531     89/<- %ebp 4/r32/esp
 9532     # . save registers
 9533     50/push-eax
 9534     56/push-esi
 9535     57/push-edi
 9536     # esi = in
 9537     8b/-> *(ebp+8) 6/r32/esi
 9538     # edi = out
 9539     8b/-> *(ebp+0xc) 7/r32/edi
 9540     # initialize some global state
 9541     c7 0/subop/copy *Curr-block-depth 1/imm32
 9542     # parse-mu-block(in, vars, out, out->body)
 9543     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 9544     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 9545 $populate-mu-function-body:end:
 9546     # . restore registers
 9547     5f/pop-to-edi
 9548     5e/pop-to-esi
 9549     58/pop-to-eax
 9550     # . epilogue
 9551     89/<- %esp 5/r32/ebp
 9552     5d/pop-to-ebp
 9553     c3/return
 9554 
 9555 # parses a block, assuming that the leading '{' has already been read by the caller
 9556 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)
 9557     # pseudocode:
 9558     #   var line: (stream byte 512)
 9559     #   var word-slice: slice
 9560     #   allocate(Heap, Stmt-size, out)
 9561     #   var out-addr: (addr block) = lookup(*out)
 9562     #   out-addr->tag = 0/block
 9563     #   out-addr->var = some unique name
 9564     #   push(vars, {out-addr->var, false})
 9565     #   while true                                  # line loop
 9566     #     clear-stream(line)
 9567     #     read-line-buffered(in, line)
 9568     #     if (line->write == 0) break               # end of file
 9569     #     word-slice = next-mu-token(line)
 9570     #     if slice-empty?(word-slice)               # end of line
 9571     #       continue
 9572     #     else if slice-starts-with?(word-slice, "#")
 9573     #       continue
 9574     #     else if slice-equal?(word-slice, "{")
 9575     #       assert(no-tokens-in(line))
 9576     #       block = parse-mu-block(in, vars, fn)
 9577     #       append-to-block(out-addr, block)
 9578     #     else if slice-equal?(word-slice, "}")
 9579     #       break
 9580     #     else if slice-ends-with?(word-slice, ":")
 9581     #       # TODO: error-check the rest of 'line'
 9582     #       --word-slice->end to skip ':'
 9583     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 9584     #       append-to-block(out-addr, named-block)
 9585     #     else if slice-equal?(word-slice, "var")
 9586     #       var-def = parse-mu-var-def(line, vars, fn)
 9587     #       append-to-block(out-addr, var-def)
 9588     #     else
 9589     #       stmt = parse-mu-stmt(line, vars, fn)
 9590     #       append-to-block(out-addr, stmt)
 9591     #   pop(vars)
 9592     #
 9593     # . prologue
 9594     55/push-ebp
 9595     89/<- %ebp 4/r32/esp
 9596     # . save registers
 9597     50/push-eax
 9598     51/push-ecx
 9599     52/push-edx
 9600     53/push-ebx
 9601     57/push-edi
 9602     # var line/ecx: (stream byte 512)
 9603     81 5/subop/subtract %esp 0x200/imm32
 9604     68/push 0x200/imm32/size
 9605     68/push 0/imm32/read
 9606     68/push 0/imm32/write
 9607     89/<- %ecx 4/r32/esp
 9608     # var word-slice/edx: slice
 9609     68/push 0/imm32/end
 9610     68/push 0/imm32/start
 9611     89/<- %edx 4/r32/esp
 9612     # allocate into out
 9613     (allocate Heap *Stmt-size *(ebp+0x14))
 9614     # var out-addr/edi: (addr block) = lookup(*out)
 9615     8b/-> *(ebp+0x14) 7/r32/edi
 9616     (lookup *edi *(edi+4))  # => eax
 9617     89/<- %edi 0/r32/eax
 9618     # out-addr->tag is 0 (block) by default
 9619     # set out-addr->var
 9620     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 9621     (new-block-name *(ebp+0x10) %eax)
 9622     # push(vars, out-addr->var)
 9623     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 9624     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 9625     (push *(ebp+0xc) 0)  # false
 9626     # increment *Curr-block-depth
 9627     ff 0/subop/increment *Curr-block-depth
 9628     {
 9629 $parse-mu-block:line-loop:
 9630       # line = read-line-buffered(in)
 9631       (clear-stream %ecx)
 9632       (read-line-buffered *(ebp+8) %ecx)
 9633 #?       (write-buffered Stderr "line: ")
 9634 #?       (write-stream-data Stderr %ecx)
 9635 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 9636 #?       (flush Stderr)
 9637 #?       (rewind-stream %ecx)
 9638       # if (line->write == 0) break
 9639       81 7/subop/compare *ecx 0/imm32
 9640       0f 84/jump-if-= break/disp32
 9641 #?       (write-buffered Stderr "vars:\n")
 9642 #?       (dump-vars *(ebp+0xc))
 9643       # word-slice = next-mu-token(line)
 9644       (next-mu-token %ecx %edx)
 9645 #?       (write-buffered Stderr "word: ")
 9646 #?       (write-slice-buffered Stderr %edx)
 9647 #?       (write-buffered Stderr Newline)
 9648 #?       (flush Stderr)
 9649       # if slice-empty?(word-slice) continue
 9650       (slice-empty? %edx)
 9651       3d/compare-eax-and 0/imm32/false
 9652       0f 85/jump-if-!= loop/disp32
 9653       # if (slice-starts-with?(word-slice, '#') continue
 9654       # . eax = *word-slice->start
 9655       8b/-> *edx 0/r32/eax
 9656       8a/copy-byte *eax 0/r32/AL
 9657       81 4/subop/and %eax 0xff/imm32
 9658       # . if (eax == '#') continue
 9659       3d/compare-eax-and 0x23/imm32/hash
 9660       0f 84/jump-if-= loop/disp32
 9661       # if slice-equal?(word-slice, "{")
 9662       {
 9663 $parse-mu-block:check-for-block:
 9664         (slice-equal? %edx "{")
 9665         3d/compare-eax-and 0/imm32/false
 9666         74/jump-if-= break/disp8
 9667         (check-no-tokens-left %ecx)
 9668         # parse new block and append
 9669         # . var tmp/eax: (handle block)
 9670         68/push 0/imm32
 9671         68/push 0/imm32
 9672         89/<- %eax 4/r32/esp
 9673         # .
 9674         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9675         (append-to-block Heap %edi  *eax *(eax+4))
 9676         # . reclaim tmp
 9677         81 0/subop/add %esp 8/imm32
 9678         # .
 9679         e9/jump $parse-mu-block:line-loop/disp32
 9680       }
 9681       # if slice-equal?(word-slice, "}") break
 9682 $parse-mu-block:check-for-end:
 9683       (slice-equal? %edx "}")
 9684       3d/compare-eax-and 0/imm32/false
 9685       0f 85/jump-if-!= break/disp32
 9686       # if slice-ends-with?(word-slice, ":") parse named block and append
 9687       {
 9688 $parse-mu-block:check-for-named-block:
 9689         # . eax = *(word-slice->end-1)
 9690         8b/-> *(edx+4) 0/r32/eax
 9691         48/decrement-eax
 9692         8a/copy-byte *eax 0/r32/AL
 9693         81 4/subop/and %eax 0xff/imm32
 9694         # . if (eax != ':') break
 9695         3d/compare-eax-and 0x3a/imm32/colon
 9696         0f 85/jump-if-!= break/disp32
 9697         # TODO: error-check the rest of 'line'
 9698         #
 9699         # skip ':'
 9700         ff 1/subop/decrement *(edx+4)  # Slice-end
 9701         # var tmp/eax: (handle block)
 9702         68/push 0/imm32
 9703         68/push 0/imm32
 9704         89/<- %eax 4/r32/esp
 9705         #
 9706         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9707         (append-to-block Heap %edi  *eax *(eax+4))
 9708         # reclaim tmp
 9709         81 0/subop/add %esp 8/imm32
 9710         #
 9711         e9/jump $parse-mu-block:line-loop/disp32
 9712       }
 9713       # if slice-equal?(word-slice, "var")
 9714       {
 9715 $parse-mu-block:check-for-var:
 9716         (slice-equal? %edx "var")
 9717         3d/compare-eax-and 0/imm32/false
 9718         74/jump-if-= break/disp8
 9719         # var tmp/eax: (handle block)
 9720         68/push 0/imm32
 9721         68/push 0/imm32
 9722         89/<- %eax 4/r32/esp
 9723         #
 9724         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 9725         (append-to-block Heap %edi  *eax *(eax+4))
 9726         # reclaim tmp
 9727         81 0/subop/add %esp 8/imm32
 9728         #
 9729         e9/jump $parse-mu-block:line-loop/disp32
 9730       }
 9731 $parse-mu-block:regular-stmt:
 9732       # otherwise
 9733       # var tmp/eax: (handle block)
 9734       68/push 0/imm32
 9735       68/push 0/imm32
 9736       89/<- %eax 4/r32/esp
 9737       #
 9738       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 9739       (append-to-block Heap %edi  *eax *(eax+4))
 9740       # reclaim tmp
 9741       81 0/subop/add %esp 8/imm32
 9742       #
 9743       e9/jump loop/disp32
 9744     } # end line loop
 9745     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 9746     # decrement *Curr-block-depth
 9747     ff 1/subop/decrement *Curr-block-depth
 9748     # pop(vars)
 9749     (pop *(ebp+0xc))  # => eax
 9750     (pop *(ebp+0xc))  # => eax
 9751     (pop *(ebp+0xc))  # => eax
 9752 $parse-mu-block:end:
 9753     # . reclaim locals
 9754     81 0/subop/add %esp 0x214/imm32
 9755     # . restore registers
 9756     5f/pop-to-edi
 9757     5b/pop-to-ebx
 9758     5a/pop-to-edx
 9759     59/pop-to-ecx
 9760     58/pop-to-eax
 9761     # . epilogue
 9762     89/<- %esp 5/r32/ebp
 9763     5d/pop-to-ebp
 9764     c3/return
 9765 
 9766 $parse-mu-block:abort:
 9767     # error("'{' or '}' should be on its own line, but got '")
 9768     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 9769     (rewind-stream %ecx)
 9770     (write-stream-data *(ebp+0x18) %ecx)
 9771     (write-buffered *(ebp+0x18) "'\n")
 9772     (flush *(ebp+0x18))
 9773     (stop *(ebp+0x1c) 1)
 9774     # never gets here
 9775 
 9776 new-block-name:  # fn: (addr function), out: (addr handle var)
 9777     # . prologue
 9778     55/push-ebp
 9779     89/<- %ebp 4/r32/esp
 9780     # . save registers
 9781     50/push-eax
 9782     51/push-ecx
 9783     52/push-edx
 9784     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 9785     8b/-> *(ebp+8) 0/r32/eax
 9786     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9787     8b/-> *eax 0/r32/eax  # String-size
 9788     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 9789     89/<- %ecx 0/r32/eax
 9790     # var name/edx: (stream byte n)
 9791     29/subtract-from %esp 1/r32/ecx
 9792     ff 6/subop/push %ecx
 9793     68/push 0/imm32/read
 9794     68/push 0/imm32/write
 9795     89/<- %edx 4/r32/esp
 9796     (clear-stream %edx)
 9797     # eax = fn->name
 9798     8b/-> *(ebp+8) 0/r32/eax
 9799     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9800     # construct result using Next-block-index (and increment it)
 9801     (write %edx "$")
 9802     (write %edx %eax)
 9803     (write %edx ":")
 9804     (write-int32-hex %edx *Next-block-index)
 9805     ff 0/subop/increment *Next-block-index
 9806     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 9807     # . eax = name->write
 9808     8b/-> *edx 0/r32/eax
 9809     # . edx = name->data
 9810     8d/copy-address *(edx+0xc) 2/r32/edx
 9811     # . eax = name->write + name->data
 9812     01/add-to %eax 2/r32/edx
 9813     # . push {edx, eax}
 9814     ff 6/subop/push %eax
 9815     ff 6/subop/push %edx
 9816     89/<- %eax 4/r32/esp
 9817     # out = new literal(s)
 9818     (new-literal Heap %eax *(ebp+0xc))
 9819 #?     8b/-> *(ebp+0xc) 0/r32/eax
 9820 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 9821 #?     (write-int32-hex-buffered Stderr *(eax+8))
 9822 #?     (write-buffered Stderr " for var ")
 9823 #?     (write-int32-hex-buffered Stderr %eax)
 9824 #?     (write-buffered Stderr Newline)
 9825 #?     (flush Stderr)
 9826 $new-block-name:end:
 9827     # . reclaim locals
 9828     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 9829     81 0/subop/add %ecx 8/imm32  # slice
 9830     01/add-to %esp 1/r32/ecx
 9831     # . restore registers
 9832     5a/pop-to-edx
 9833     59/pop-to-ecx
 9834     58/pop-to-eax
 9835     # . epilogue
 9836     89/<- %esp 5/r32/ebp
 9837     5d/pop-to-ebp
 9838     c3/return
 9839 
 9840 check-no-tokens-left:  # line: (addr stream byte)
 9841     # . prologue
 9842     55/push-ebp
 9843     89/<- %ebp 4/r32/esp
 9844     # . save registers
 9845     50/push-eax
 9846     51/push-ecx
 9847     # var s/ecx: slice
 9848     68/push 0/imm32/end
 9849     68/push 0/imm32/start
 9850     89/<- %ecx 4/r32/esp
 9851     #
 9852     (next-mu-token *(ebp+8) %ecx)
 9853     # if slice-empty?(s) return
 9854     (slice-empty? %ecx)
 9855     3d/compare-eax-and 0/imm32/false
 9856     75/jump-if-!= $check-no-tokens-left:end/disp8
 9857     # if (slice-starts-with?(s, '#') return
 9858     # . eax = *s->start
 9859     8b/-> *edx 0/r32/eax
 9860     8a/copy-byte *eax 0/r32/AL
 9861     81 4/subop/and %eax 0xff/imm32
 9862     # . if (eax == '#') continue
 9863     3d/compare-eax-and 0x23/imm32/hash
 9864     74/jump-if-= $check-no-tokens-left:end/disp8
 9865     # abort
 9866     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 9867     (rewind-stream %ecx)
 9868     (write-stream 2 %ecx)
 9869     (write-buffered Stderr "'\n")
 9870     (flush Stderr)
 9871     # . syscall(exit, 1)
 9872     bb/copy-to-ebx  1/imm32
 9873     e8/call syscall_exit/disp32
 9874     # never gets here
 9875 $check-no-tokens-left:end:
 9876     # . reclaim locals
 9877     81 0/subop/add %esp 8/imm32
 9878     # . restore registers
 9879     59/pop-to-ecx
 9880     58/pop-to-eax
 9881     # . epilogue
 9882     89/<- %esp 5/r32/ebp
 9883     5d/pop-to-ebp
 9884     c3/return
 9885 
 9886 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)
 9887     # pseudocode:
 9888     #   var v: (handle var)
 9889     #   new-literal(name, v)
 9890     #   push(vars, {v, false})
 9891     #   parse-mu-block(in, vars, fn, out)
 9892     #   pop(vars)
 9893     #   out->tag = block
 9894     #   out->var = v
 9895     #
 9896     # . prologue
 9897     55/push-ebp
 9898     89/<- %ebp 4/r32/esp
 9899     # . save registers
 9900     50/push-eax
 9901     51/push-ecx
 9902     57/push-edi
 9903     # var v/ecx: (handle var)
 9904     68/push 0/imm32
 9905     68/push 0/imm32
 9906     89/<- %ecx 4/r32/esp
 9907     #
 9908     (new-literal Heap *(ebp+8) %ecx)
 9909     # push(vars, v)
 9910     (push *(ebp+0x10) *ecx)
 9911     (push *(ebp+0x10) *(ecx+4))
 9912     (push *(ebp+0x10) 0)  # false
 9913     #
 9914     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 9915     # pop v off vars
 9916     (pop *(ebp+0x10))  # => eax
 9917     (pop *(ebp+0x10))  # => eax
 9918     (pop *(ebp+0x10))  # => eax
 9919     # var out-addr/edi: (addr stmt) = lookup(*out)
 9920     8b/-> *(ebp+0x18) 7/r32/edi
 9921     (lookup *edi *(edi+4))  # => eax
 9922     89/<- %edi 0/r32/eax
 9923     # out-addr->tag = named-block
 9924     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 9925     # out-addr->var = v
 9926     8b/-> *ecx 0/r32/eax
 9927     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 9928     8b/-> *(ecx+4) 0/r32/eax
 9929     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 9930 $parse-mu-named-block:end:
 9931     # . reclaim locals
 9932     81 0/subop/add %esp 8/imm32
 9933     # . restore registers
 9934     5f/pop-to-edi
 9935     59/pop-to-ecx
 9936     58/pop-to-eax
 9937     # . epilogue
 9938     89/<- %esp 5/r32/ebp
 9939     5d/pop-to-ebp
 9940     c3/return
 9941 
 9942 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)
 9943     # . prologue
 9944     55/push-ebp
 9945     89/<- %ebp 4/r32/esp
 9946     # . save registers
 9947     50/push-eax
 9948     51/push-ecx
 9949     52/push-edx
 9950     53/push-ebx
 9951     57/push-edi
 9952     # edi = out
 9953     8b/-> *(ebp+0x10) 7/r32/edi
 9954     # var word-slice/ecx: slice
 9955     68/push 0/imm32/end
 9956     68/push 0/imm32/start
 9957     89/<- %ecx 4/r32/esp
 9958     # var v/edx: (handle var)
 9959     68/push 0/imm32
 9960     68/push 0/imm32
 9961     89/<- %edx 4/r32/esp
 9962     # v = parse-var-with-type(next-mu-token(line))
 9963     (next-mu-token *(ebp+8) %ecx)
 9964     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 9965     # var v-addr/eax: (addr var)
 9966     (lookup *edx *(edx+4))  # => eax
 9967     # v->block-depth = *Curr-block-depth
 9968     8b/-> *Curr-block-depth 3/r32/ebx
 9969     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 9970     # either v has no register and there's no more to this line
 9971     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 9972     3d/compare-eax-and 0/imm32
 9973     {
 9974       75/jump-if-!= break/disp8
 9975       # TODO: disallow vars of type 'byte' on the stack
 9976       # ensure that there's nothing else on this line
 9977       (next-mu-token *(ebp+8) %ecx)
 9978       (slice-empty? %ecx)  # => eax
 9979       3d/compare-eax-and 0/imm32/false
 9980       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 9981       #
 9982       (new-var-def Heap  *edx *(edx+4)  %edi)
 9983       e9/jump $parse-mu-var-def:update-vars/disp32
 9984     }
 9985     # or v has a register and there's more to this line
 9986     {
 9987       0f 84/jump-if-= break/disp32
 9988       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 9989       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 9990       # ensure that the next word is '<-'
 9991       (next-mu-token *(ebp+8) %ecx)
 9992       (slice-equal? %ecx "<-")  # => eax
 9993       3d/compare-eax-and 0/imm32/false
 9994       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 9995       #
 9996       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 9997       (lookup *edi *(edi+4))  # => eax
 9998       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9999     }
10000 $parse-mu-var-def:update-vars:
10001     # push 'v' at end of function
10002     (push *(ebp+0xc) *edx)
10003     (push *(ebp+0xc) *(edx+4))
10004     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
10005 $parse-mu-var-def:end:
10006     # . reclaim locals
10007     81 0/subop/add %esp 0x10/imm32
10008     # . restore registers
10009     5f/pop-to-edi
10010     5b/pop-to-ebx
10011     5a/pop-to-edx
10012     59/pop-to-ecx
10013     58/pop-to-eax
10014     # . epilogue
10015     89/<- %esp 5/r32/ebp
10016     5d/pop-to-ebp
10017     c3/return
10018 
10019 $parse-mu-var-def:error1:
10020     (rewind-stream *(ebp+8))
10021     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
10022     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
10023     (flush *(ebp+0x18))
10024     (write-stream-data *(ebp+0x18) *(ebp+8))
10025     (write-buffered *(ebp+0x18) "'\n")
10026     (flush *(ebp+0x18))
10027     (stop *(ebp+0x1c) 1)
10028     # never gets here
10029 
10030 $parse-mu-var-def:error2:
10031     (rewind-stream *(ebp+8))
10032     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
10033     (write-buffered *(ebp+0x18) "fn ")
10034     8b/-> *(ebp+0x14) 0/r32/eax
10035     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10036     (write-buffered *(ebp+0x18) %eax)
10037     (write-buffered *(ebp+0x18) ": var ")
10038     # var v-addr/eax: (addr var) = lookup(v)
10039     (lookup *edx *(edx+4))  # => eax
10040     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10041     (write-buffered *(ebp+0x18) %eax)
10042     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
10043     (flush *(ebp+0x18))
10044     (stop *(ebp+0x1c) 1)
10045     # never gets here
10046 
10047 test-parse-mu-var-def:
10048     # 'var n: int'
10049     # . prologue
10050     55/push-ebp
10051     89/<- %ebp 4/r32/esp
10052     # setup
10053     (clear-stream _test-input-stream)
10054     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
10055     c7 0/subop/copy *Curr-block-depth 1/imm32
10056     # var out/esi: (handle stmt)
10057     68/push 0/imm32
10058     68/push 0/imm32
10059     89/<- %esi 4/r32/esp
10060     # var vars/ecx: (stack (addr var) 16)
10061     81 5/subop/subtract %esp 0xc0/imm32
10062     68/push 0xc0/imm32/size
10063     68/push 0/imm32/top
10064     89/<- %ecx 4/r32/esp
10065     (clear-stack %ecx)
10066     # convert
10067     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
10068     # var out-addr/esi: (addr stmt)
10069     (lookup *esi *(esi+4))  # => eax
10070     89/<- %esi 0/r32/eax
10071     #
10072     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
10073     # var v/ecx: (addr var) = lookup(out->var)
10074     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
10075     89/<- %ecx 0/r32/eax
10076     # v->name
10077     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10078     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
10079     # v->register
10080     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
10081     # v->block-depth
10082     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
10083     # v->type == int
10084     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10085     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
10086     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
10087     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
10088     # . epilogue
10089     89/<- %esp 5/r32/ebp
10090     5d/pop-to-ebp
10091     c3/return
10092 
10093 test-parse-mu-reg-var-def:
10094     # 'var n/eax: int <- copy 0'
10095     # . prologue
10096     55/push-ebp
10097     89/<- %ebp 4/r32/esp
10098     # setup
10099     (clear-stream _test-input-stream)
10100     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
10101     c7 0/subop/copy *Curr-block-depth 1/imm32
10102     # var out/esi: (handle stmt)
10103     68/push 0/imm32
10104     68/push 0/imm32
10105     89/<- %esi 4/r32/esp
10106     # var vars/ecx: (stack (addr var) 16)
10107     81 5/subop/subtract %esp 0xc0/imm32
10108     68/push 0xc0/imm32/size
10109     68/push 0/imm32/top
10110     89/<- %ecx 4/r32/esp
10111     (clear-stack %ecx)
10112     # convert
10113     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
10114     # var out-addr/esi: (addr stmt)
10115     (lookup *esi *(esi+4))  # => eax
10116     89/<- %esi 0/r32/eax
10117     #
10118     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
10119     # var v/ecx: (addr var) = lookup(out->outputs->value)
10120     # . eax: (addr stmt-var) = lookup(out->outputs)
10121     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10122     # .
10123     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
10124     # . eax: (addr var) = lookup(eax->value)
10125     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10126     # . ecx = eax
10127     89/<- %ecx 0/r32/eax
10128     # v->name
10129     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10130     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
10131     # v->register
10132     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10133     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
10134     # v->block-depth
10135     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
10136     # v->type == int
10137     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10138     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
10139     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
10140     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
10141     # . epilogue
10142     89/<- %esp 5/r32/ebp
10143     5d/pop-to-ebp
10144     c3/return
10145 
10146 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)
10147     # Carefully push any outputs on the vars stack _after_ reading the inputs
10148     # that may conflict with them.
10149     #
10150     # The only situation in which outputs are pushed here (when it's not a
10151     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
10152     # output is a function output.
10153     #
10154     # pseudocode:
10155     #   var name: slice
10156     #   allocate(Heap, Stmt-size, out)
10157     #   var out-addr: (addr stmt) = lookup(*out)
10158     #   out-addr->tag = stmt
10159     #   if stmt-has-outputs?(line)
10160     #     while true
10161     #       name = next-mu-token(line)
10162     #       if (name == '<-') break
10163     #       assert(is-identifier?(name))
10164     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
10165     #       out-addr->outputs = append(v, out-addr->outputs)
10166     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
10167     #   for output in stmt->outputs:
10168     #     maybe-define-var(output, vars)
10169     #
10170     # . prologue
10171     55/push-ebp
10172     89/<- %ebp 4/r32/esp
10173     # . save registers
10174     50/push-eax
10175     51/push-ecx
10176     52/push-edx
10177     53/push-ebx
10178     57/push-edi
10179     # var name/ecx: slice
10180     68/push 0/imm32/end
10181     68/push 0/imm32/start
10182     89/<- %ecx 4/r32/esp
10183     # var is-deref?/edx: boolean = false
10184     ba/copy-to-edx 0/imm32/false
10185     # var v: (handle var)
10186     68/push 0/imm32
10187     68/push 0/imm32
10188     89/<- %ebx 4/r32/esp
10189     #
10190     (allocate Heap *Stmt-size *(ebp+0x14))
10191     # var out-addr/edi: (addr stmt) = lookup(*out)
10192     8b/-> *(ebp+0x14) 7/r32/edi
10193     (lookup *edi *(edi+4))  # => eax
10194     89/<- %edi 0/r32/eax
10195     # out-addr->tag = 1/stmt
10196     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
10197     {
10198       (stmt-has-outputs? *(ebp+8))
10199       3d/compare-eax-and 0/imm32/false
10200       0f 84/jump-if-= break/disp32
10201       {
10202 $parse-mu-stmt:read-outputs:
10203         # name = next-mu-token(line)
10204         (next-mu-token *(ebp+8) %ecx)
10205         # if slice-empty?(word-slice) break
10206         (slice-empty? %ecx)  # => eax
10207         3d/compare-eax-and 0/imm32/false
10208         0f 85/jump-if-!= break/disp32
10209         # if (name == "<-") break
10210         (slice-equal? %ecx "<-")  # => eax
10211         3d/compare-eax-and 0/imm32/false
10212         0f 85/jump-if-!= break/disp32
10213         # is-deref? = false
10214         ba/copy-to-edx 0/imm32/false
10215         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10216         8b/-> *ecx 0/r32/eax  # Slice-start
10217         8a/copy-byte *eax 0/r32/AL
10218         81 4/subop/and %eax 0xff/imm32
10219         3d/compare-eax-and 0x2a/imm32/asterisk
10220         {
10221           75/jump-if-!= break/disp8
10222           ff 0/subop/increment *ecx
10223           ba/copy-to-edx 1/imm32/true
10224         }
10225         # assert(is-identifier?(name))
10226         (is-identifier? %ecx)  # => eax
10227         3d/compare-eax-and 0/imm32/false
10228         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
10229         #
10230         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
10231         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
10232         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
10233         #
10234         e9/jump loop/disp32
10235       }
10236     }
10237     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
10238 $parse-mu-stmt:define-outputs:
10239     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
10240     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10241     89/<- %edi 0/r32/eax
10242     {
10243 $parse-mu-stmt:define-outputs-loop:
10244       # if (output == null) break
10245       81 7/subop/compare %edi 0/imm32
10246       74/jump-if-= break/disp8
10247       #
10248       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
10249                                                     # and must be in vars. This call will be a no-op, but safe.
10250       # output = output->next
10251       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
10252       89/<- %edi 0/r32/eax
10253       #
10254       eb/jump loop/disp8
10255     }
10256 $parse-mu-stmt:end:
10257     # . reclaim locals
10258     81 0/subop/add %esp 0x10/imm32
10259     # . restore registers
10260     5f/pop-to-edi
10261     5b/pop-to-ebx
10262     5a/pop-to-edx
10263     59/pop-to-ecx
10264     58/pop-to-eax
10265     # . epilogue
10266     89/<- %esp 5/r32/ebp
10267     5d/pop-to-ebp
10268     c3/return
10269 
10270 $parse-mu-stmt:abort:
10271     # error("invalid identifier '" name "'\n")
10272     (write-buffered *(ebp+0x18) "invalid identifier '")
10273     (write-slice-buffered *(ebp+0x18) %ecx)
10274     (write-buffered *(ebp+0x18) "'\n")
10275     (flush *(ebp+0x18))
10276     (stop *(ebp+0x1c) 1)
10277     # never gets here
10278 
10279 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)
10280     # pseudocode:
10281     #   stmt->name = slice-to-string(next-mu-token(line))
10282     #   while true
10283     #     name = next-mu-token(line)
10284     #     v = lookup-var-or-literal(name)
10285     #     stmt->inouts = append(v, stmt->inouts)
10286     #
10287     # . prologue
10288     55/push-ebp
10289     89/<- %ebp 4/r32/esp
10290     # . save registers
10291     50/push-eax
10292     51/push-ecx
10293     52/push-edx
10294     53/push-ebx
10295     56/push-esi
10296     57/push-edi
10297     # edi = stmt
10298     8b/-> *(ebp+8) 7/r32/edi
10299     # var name/ecx: slice
10300     68/push 0/imm32/end
10301     68/push 0/imm32/start
10302     89/<- %ecx 4/r32/esp
10303     # var is-deref?/edx: boolean = false
10304     ba/copy-to-edx 0/imm32/false
10305     # var v/esi: (handle var)
10306     68/push 0/imm32
10307     68/push 0/imm32
10308     89/<- %esi 4/r32/esp
10309 $add-operation-and-inputs-to-stmt:read-operation:
10310     (next-mu-token *(ebp+0xc) %ecx)
10311     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
10312     (slice-to-string Heap %ecx %eax)
10313     # var is-get?/ebx: boolean = (name == "get")
10314     (slice-equal? %ecx "get")  # => eax
10315     89/<- %ebx 0/r32/eax
10316     {
10317 $add-operation-and-inputs-to-stmt:read-inouts:
10318       # name = next-mu-token(line)
10319       (next-mu-token *(ebp+0xc) %ecx)
10320       # if slice-empty?(word-slice) break
10321       (slice-empty? %ecx)  # => eax
10322       3d/compare-eax-and 0/imm32/false
10323       0f 85/jump-if-!= break/disp32
10324       # if (name == "<-") abort
10325       (slice-equal? %ecx "<-")
10326       3d/compare-eax-and 0/imm32/false
10327       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
10328       # if (is-get? && second operand) lookup or create offset
10329       {
10330         81 7/subop/compare %ebx 0/imm32/false
10331         74/jump-if-= break/disp8
10332         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10333         3d/compare-eax-and 0/imm32
10334         74/jump-if-= break/disp8
10335         (lookup-or-create-constant %eax %ecx %esi)
10336 #?         (lookup *esi *(esi+4))
10337 #?         (write-buffered Stderr "creating new output var ")
10338 #?         (write-int32-hex-buffered Stderr %eax)
10339 #?         (write-buffered Stderr " for field called ")
10340 #?         (write-slice-buffered Stderr %ecx)
10341 #?         (write-buffered Stderr "; var name ")
10342 #?         (lookup *eax *(eax+4))  # Var-name
10343 #?         (write-buffered Stderr %eax)
10344 #?         (write-buffered Stderr Newline)
10345 #?         (flush Stderr)
10346         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
10347       }
10348       # is-deref? = false
10349       ba/copy-to-edx 0/imm32/false
10350       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
10351       8b/-> *ecx 0/r32/eax  # Slice-start
10352       8a/copy-byte *eax 0/r32/AL
10353       81 4/subop/and %eax 0xff/imm32
10354       3d/compare-eax-and 0x2a/imm32/asterisk
10355       {
10356         75/jump-if-!= break/disp8
10357 $add-operation-and-inputs-to-stmt:inout-is-deref:
10358         ff 0/subop/increment *ecx
10359         ba/copy-to-edx 1/imm32/true
10360       }
10361       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10362 $add-operation-and-inputs-to-stmt:save-var:
10363       8d/copy-address *(edi+0xc) 0/r32/eax
10364       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
10365       #
10366       e9/jump loop/disp32
10367     }
10368 $add-operation-and-inputs-to-stmt:end:
10369     # . reclaim locals
10370     81 0/subop/add %esp 0x10/imm32
10371     # . restore registers
10372     5f/pop-to-edi
10373     5e/pop-to-esi
10374     5b/pop-to-ebx
10375     5a/pop-to-edx
10376     59/pop-to-ecx
10377     58/pop-to-eax
10378     # . epilogue
10379     89/<- %esp 5/r32/ebp
10380     5d/pop-to-ebp
10381     c3/return
10382 
10383 $add-operation-and-inputs-to-stmt:abort:
10384     # error("fn ___: invalid identifier in '" line "'\n")
10385     (write-buffered *(ebp+0x18) "fn ")
10386     8b/-> *(ebp+0x14) 0/r32/eax
10387     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10388     (write-buffered *(ebp+0x18) %eax)
10389     (rewind-stream *(ebp+0xc))
10390     (write-buffered *(ebp+0x18) ": invalid identifier in '")
10391     (write-stream-data *(ebp+0x18) *(ebp+0xc))
10392     (write-buffered *(ebp+0x18) "'\n")
10393     (flush *(ebp+0x18))
10394     (stop *(ebp+0x1c) 1)
10395     # never gets here
10396 
10397 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
10398     # . prologue
10399     55/push-ebp
10400     89/<- %ebp 4/r32/esp
10401     # . save registers
10402     51/push-ecx
10403     # var word-slice/ecx: slice
10404     68/push 0/imm32/end
10405     68/push 0/imm32/start
10406     89/<- %ecx 4/r32/esp
10407     # result = false
10408     b8/copy-to-eax 0/imm32/false
10409     (rewind-stream *(ebp+8))
10410     {
10411       (next-mu-token *(ebp+8) %ecx)
10412       # if slice-empty?(word-slice) break
10413       (slice-empty? %ecx)
10414       3d/compare-eax-and 0/imm32/false
10415       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10416       0f 85/jump-if-!= break/disp32
10417       # if slice-starts-with?(word-slice, '#') break
10418       # . eax = *word-slice->start
10419       8b/-> *ecx 0/r32/eax
10420       8a/copy-byte *eax 0/r32/AL
10421       81 4/subop/and %eax 0xff/imm32
10422       # . if (eax == '#') break
10423       3d/compare-eax-and 0x23/imm32/hash
10424       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
10425       0f 84/jump-if-= break/disp32
10426       # if slice-equal?(word-slice, '<-') return true
10427       (slice-equal? %ecx "<-")
10428       3d/compare-eax-and 0/imm32/false
10429       74/jump-if-= loop/disp8
10430       b8/copy-to-eax 1/imm32/true
10431     }
10432 $stmt-has-outputs:end:
10433     (rewind-stream *(ebp+8))
10434     # . reclaim locals
10435     81 0/subop/add %esp 8/imm32
10436     # . restore registers
10437     59/pop-to-ecx
10438     # . epilogue
10439     89/<- %esp 5/r32/ebp
10440     5d/pop-to-ebp
10441     c3/return
10442 
10443 # if 'name' starts with a digit, create a new literal var for it
10444 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
10445 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)
10446     # . prologue
10447     55/push-ebp
10448     89/<- %ebp 4/r32/esp
10449     # . save registers
10450     50/push-eax
10451     51/push-ecx
10452     56/push-esi
10453     # esi = name
10454     8b/-> *(ebp+8) 6/r32/esi
10455     # if slice-empty?(name) abort
10456     (slice-empty? %esi)  # => eax
10457     3d/compare-eax-and 0/imm32/false
10458     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
10459     # var c/ecx: byte = *name->start
10460     8b/-> *esi 1/r32/ecx
10461     8a/copy-byte *ecx 1/r32/CL
10462     81 4/subop/and %ecx 0xff/imm32
10463     # if (is-decimal-digit?(c) || c == '-') return new var(name)
10464     {
10465       81 7/subop/compare %ecx 0x2d/imm32/dash
10466       74/jump-if-= $lookup-var-or-literal:literal/disp8
10467       (is-decimal-digit? %ecx)  # => eax
10468       3d/compare-eax-and 0/imm32/false
10469       74/jump-if-= break/disp8
10470 $lookup-var-or-literal:literal:
10471       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10472       eb/jump $lookup-var-or-literal:end/disp8
10473     }
10474     # else if (c == '"') return new var(name)
10475     {
10476       81 7/subop/compare %ecx 0x22/imm32/dquote
10477       75/jump-if-!= break/disp8
10478 $lookup-var-or-literal:literal-string:
10479       (new-literal Heap %esi *(ebp+0x10))
10480       eb/jump $lookup-var-or-literal:end/disp8
10481     }
10482     # otherwise return lookup-var(name, vars)
10483     {
10484 $lookup-var-or-literal:var:
10485       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10486     }
10487 $lookup-var-or-literal:end:
10488     # . restore registers
10489     5e/pop-to-esi
10490     59/pop-to-ecx
10491     58/pop-to-eax
10492     # . epilogue
10493     89/<- %esp 5/r32/ebp
10494     5d/pop-to-ebp
10495     c3/return
10496 
10497 $lookup-var-or-literal:abort:
10498     (write-buffered *(ebp+0x18) "fn ")
10499     8b/-> *(ebp+0x14) 0/r32/eax
10500     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10501     (write-buffered *(ebp+0x18) %eax)
10502     (write-buffered *(ebp+0x18) ": empty variable!")
10503     (flush *(ebp+0x18))
10504     (stop *(ebp+0x1c) 1)
10505     # never gets here
10506 
10507 # return first 'name' from the top (back) of 'vars' and abort if not found
10508 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)
10509     # . prologue
10510     55/push-ebp
10511     89/<- %ebp 4/r32/esp
10512     # . save registers
10513     50/push-eax
10514     #
10515     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10516     # if (*out == 0) abort
10517     8b/-> *(ebp+0x10) 0/r32/eax
10518     81 7/subop/compare *eax 0/imm32
10519     74/jump-if-= $lookup-var:abort/disp8
10520 $lookup-var:end:
10521     # . restore registers
10522     58/pop-to-eax
10523     # . epilogue
10524     89/<- %esp 5/r32/ebp
10525     5d/pop-to-ebp
10526     c3/return
10527 
10528 $lookup-var:abort:
10529     (write-buffered *(ebp+0x18) "fn ")
10530     8b/-> *(ebp+0x14) 0/r32/eax
10531     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10532     (write-buffered *(ebp+0x18) %eax)
10533     (write-buffered *(ebp+0x18) ": unknown variable '")
10534     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10535     (write-buffered *(ebp+0x18) "'\n")
10536     (flush *(ebp+0x18))
10537     (stop *(ebp+0x1c) 1)
10538     # never gets here
10539 
10540 # return first 'name' from the top (back) of 'vars', and 0/null if not found
10541 # ensure that 'name' if in a register is the topmost variable in that register
10542 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)
10543     # pseudocode:
10544     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10545     #   var min = vars->data
10546     #   while curr >= min
10547     #     var v: (handle var) = *curr
10548     #     if v->name == name
10549     #       return
10550     #     curr -= 12
10551     #
10552     # . prologue
10553     55/push-ebp
10554     89/<- %ebp 4/r32/esp
10555     # . save registers
10556     50/push-eax
10557     51/push-ecx
10558     52/push-edx
10559     53/push-ebx
10560     56/push-esi
10561     57/push-edi
10562     # clear out
10563     (zero-out *(ebp+0x10) *Handle-size)
10564     # esi = vars
10565     8b/-> *(ebp+0xc) 6/r32/esi
10566     # ebx = vars->top
10567     8b/-> *esi 3/r32/ebx
10568     # if (vars->top > vars->size) abort
10569     3b/compare<- *(esi+4) 0/r32/eax
10570     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
10571     # var min/edx: (addr handle var) = vars->data
10572     8d/copy-address *(esi+8) 2/r32/edx
10573     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10574     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10575     # var var-in-reg/edi: 8 addrs
10576     68/push 0/imm32
10577     68/push 0/imm32
10578     68/push 0/imm32
10579     68/push 0/imm32
10580     68/push 0/imm32
10581     68/push 0/imm32
10582     68/push 0/imm32
10583     68/push 0/imm32
10584     89/<- %edi 4/r32/esp
10585     {
10586 $lookup-var-helper:loop:
10587       # if (curr < min) return
10588       39/compare %ebx 2/r32/edx
10589       0f 82/jump-if-addr< break/disp32
10590       # var v/ecx: (addr var) = lookup(*curr)
10591       (lookup *ebx *(ebx+4))  # => eax
10592       89/<- %ecx 0/r32/eax
10593       # var vn/eax: (addr array byte) = lookup(v->name)
10594       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10595       # if (vn == name) return curr
10596       (slice-equal? *(ebp+8) %eax)  # => eax
10597       3d/compare-eax-and 0/imm32/false
10598       {
10599         74/jump-if-= break/disp8
10600 $lookup-var-helper:found:
10601         # var vr/eax: (addr array byte) = lookup(v->register)
10602         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10603         3d/compare-eax-and 0/imm32
10604         {
10605           74/jump-if-= break/disp8
10606 $lookup-var-helper:found-register:
10607           # var reg/eax: int = get(Registers, vr)
10608           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10609           8b/-> *eax 0/r32/eax
10610           # if (var-in-reg[reg]) error
10611           8b/-> *(edi+eax<<2) 0/r32/eax
10612           3d/compare-eax-and 0/imm32
10613           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
10614         }
10615 $lookup-var-helper:return:
10616         # esi = out
10617         8b/-> *(ebp+0x10) 6/r32/esi
10618         # *out = *curr
10619         8b/-> *ebx 0/r32/eax
10620         89/<- *esi 0/r32/eax
10621         8b/-> *(ebx+4) 0/r32/eax
10622         89/<- *(esi+4) 0/r32/eax
10623         # return
10624         eb/jump $lookup-var-helper:end/disp8
10625       }
10626       # 'name' not yet found; update var-in-reg if v in register
10627       # . var vr/eax: (addr array byte) = lookup(v->register)
10628       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10629       # . if (var == 0) continue
10630       3d/compare-eax-and 0/imm32
10631       74/jump-if-= $lookup-var-helper:continue/disp8
10632       # . var reg/eax: int = get(Registers, vr)
10633       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
10634       8b/-> *eax 0/r32/eax
10635       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
10636       81 7/subop/compare *(edi+eax<<2) 0/imm32
10637       75/jump-if-!= $lookup-var-helper:continue/disp8
10638       89/<- *(edi+eax<<2) 1/r32/ecx
10639 $lookup-var-helper:continue:
10640       # curr -= 12
10641       81 5/subop/subtract %ebx 0xc/imm32
10642       e9/jump loop/disp32
10643     }
10644 $lookup-var-helper:end:
10645     # . reclaim locals
10646     81 0/subop/add %esp 0x20/imm32
10647     # . restore registers
10648     5f/pop-to-edi
10649     5e/pop-to-esi
10650     5b/pop-to-ebx
10651     5a/pop-to-edx
10652     59/pop-to-ecx
10653     58/pop-to-eax
10654     # . epilogue
10655     89/<- %esp 5/r32/ebp
10656     5d/pop-to-ebp
10657     c3/return
10658 
10659 $lookup-var-helper:error1:
10660     (write-buffered *(ebp+0x18) "fn ")
10661     8b/-> *(ebp+0x14) 0/r32/eax
10662     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10663     (write-buffered *(ebp+0x18) %eax)
10664     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
10665     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10666     (write-buffered *(ebp+0x18) "'\n")
10667     (flush *(ebp+0x18))
10668     (stop *(ebp+0x1c) 1)
10669     # never gets here
10670 
10671 $lookup-var-helper:error2:
10672     # eax contains the conflicting var at this point
10673     (write-buffered *(ebp+0x18) "fn ")
10674     50/push-eax
10675     8b/-> *(ebp+0x14) 0/r32/eax
10676     (lookup *eax *(eax+4))  # Function-name Function-name => eax
10677     (write-buffered *(ebp+0x18) %eax)
10678     58/pop-eax
10679     (write-buffered *(ebp+0x18) ": register ")
10680     50/push-eax
10681     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10682     (write-buffered *(ebp+0x18) %eax)
10683     58/pop-to-eax
10684     (write-buffered *(ebp+0x18) " reads var '")
10685     (write-slice-buffered *(ebp+0x18) *(ebp+8))
10686     (write-buffered *(ebp+0x18) "' after writing var '")
10687     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10688     (write-buffered *(ebp+0x18) %eax)
10689     (write-buffered *(ebp+0x18) "'\n")
10690     (flush *(ebp+0x18))
10691     (stop *(ebp+0x1c) 1)
10692     # never gets here
10693 
10694 dump-vars:  # vars: (addr stack live-var)
10695     # pseudocode:
10696     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10697     #   var min = vars->data
10698     #   while curr >= min
10699     #     var v: (handle var) = *curr
10700     #     print v
10701     #     curr -= 12
10702     #
10703     # . prologue
10704     55/push-ebp
10705     89/<- %ebp 4/r32/esp
10706     # . save registers
10707     52/push-edx
10708     53/push-ebx
10709     56/push-esi
10710     # esi = vars
10711     8b/-> *(ebp+8) 6/r32/esi
10712     # ebx = vars->top
10713     8b/-> *esi 3/r32/ebx
10714     # var min/edx: (addr handle var) = vars->data
10715     8d/copy-address *(esi+8) 2/r32/edx
10716     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
10717     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
10718     {
10719 $dump-vars:loop:
10720       # if (curr < min) return
10721       39/compare %ebx 2/r32/edx
10722       0f 82/jump-if-addr< break/disp32
10723       #
10724       (write-buffered Stderr "  var@")
10725       (dump-var 2 %ebx)
10726       # curr -= 12
10727       81 5/subop/subtract %ebx 0xc/imm32
10728       e9/jump loop/disp32
10729     }
10730 $dump-vars:end:
10731     # . restore registers
10732     5e/pop-to-esi
10733     5b/pop-to-ebx
10734     5a/pop-to-edx
10735     # . epilogue
10736     89/<- %esp 5/r32/ebp
10737     5d/pop-to-ebp
10738     c3/return
10739 
10740 == data
10741 # Like Registers, but no esp or ebp
10742 Mu-registers:  # (addr stream {(handle array byte), int})
10743   # a table is a stream
10744   0x48/imm32/write
10745   0/imm32/read
10746   0x48/imm32/length
10747   # data
10748   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
10749   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
10750   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
10751   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
10752   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
10753   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
10754   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
10755 
10756 $Mu-register-eax:
10757   0x11/imm32/alloc-id
10758   3/imm32/size
10759   0x65/e 0x61/a 0x78/x
10760 
10761 $Mu-register-ecx:
10762   0x11/imm32/alloc-id
10763   3/imm32/size
10764   0x65/e 0x63/c 0x78/x
10765 
10766 $Mu-register-edx:
10767   0x11/imm32/alloc-id
10768   3/imm32/size
10769   0x65/e 0x64/d 0x78/x
10770 
10771 $Mu-register-ebx:
10772   0x11/imm32/alloc-id
10773   3/imm32/size
10774   0x65/e 0x62/b 0x78/x
10775 
10776 $Mu-register-esi:
10777   0x11/imm32/alloc-id
10778   3/imm32/size
10779   0x65/e 0x73/s 0x69/i
10780 
10781 $Mu-register-edi:
10782   0x11/imm32/alloc-id
10783   3/imm32/size
10784   0x65/e 0x64/d 0x69/i
10785 
10786 == code
10787 
10788 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
10789 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)
10790     # . prologue
10791     55/push-ebp
10792     89/<- %ebp 4/r32/esp
10793     # . save registers
10794     50/push-eax
10795     #
10796     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
10797     {
10798       # if (out != 0) return
10799       8b/-> *(ebp+0x14) 0/r32/eax
10800       81 7/subop/compare *eax 0/imm32
10801       75/jump-if-!= break/disp8
10802       # if name is one of fn's outputs, return it
10803       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
10804       8b/-> *(ebp+0x14) 0/r32/eax
10805       81 7/subop/compare *eax 0/imm32
10806       # otherwise abort
10807       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
10808     }
10809 $lookup-or-define-var:end:
10810     # . restore registers
10811     58/pop-to-eax
10812     # . epilogue
10813     89/<- %esp 5/r32/ebp
10814     5d/pop-to-ebp
10815     c3/return
10816 
10817 $lookup-or-define-var:abort:
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 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
10826     # . prologue
10827     55/push-ebp
10828     89/<- %ebp 4/r32/esp
10829     # . save registers
10830     50/push-eax
10831     51/push-ecx
10832     # var curr/ecx: (addr list var) = lookup(fn->outputs)
10833     8b/-> *(ebp+8) 1/r32/ecx
10834     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
10835     89/<- %ecx 0/r32/eax
10836     # while curr != null
10837     {
10838       81 7/subop/compare %ecx 0/imm32
10839       74/jump-if-= break/disp8
10840       # var v/eax: (addr var) = lookup(curr->value)
10841       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10842       # var s/eax: (addr array byte) = lookup(v->name)
10843       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10844       # if (s == name) return curr->value
10845       (slice-equal? *(ebp+0xc) %eax)  # => eax
10846       3d/compare-eax-and 0/imm32/false
10847       {
10848         74/jump-if-= break/disp8
10849         # var edi = out
10850         57/push-edi
10851         8b/-> *(ebp+0x10) 7/r32/edi
10852         # *out = curr->value
10853         8b/-> *ecx 0/r32/eax
10854         89/<- *edi 0/r32/eax
10855         8b/-> *(ecx+4) 0/r32/eax
10856         89/<- *(edi+4) 0/r32/eax
10857         #
10858         5f/pop-to-edi
10859         eb/jump $find-in-function-outputs:end/disp8
10860       }
10861       # curr = curr->next
10862       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10863       89/<- %ecx 0/r32/eax
10864       #
10865       eb/jump loop/disp8
10866     }
10867     b8/copy-to-eax 0/imm32
10868 $find-in-function-outputs:end:
10869     # . restore registers
10870     59/pop-to-ecx
10871     58/pop-to-eax
10872     # . epilogue
10873     89/<- %esp 5/r32/ebp
10874     5d/pop-to-ebp
10875     c3/return
10876 
10877 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
10878 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
10879     # . prologue
10880     55/push-ebp
10881     89/<- %ebp 4/r32/esp
10882     # . save registers
10883     50/push-eax
10884     # var out-addr/eax: (addr var)
10885     (lookup *(ebp+8) *(ebp+0xc))  # => eax
10886     #
10887     (binding-exists? %eax *(ebp+0x10))  # => eax
10888     3d/compare-eax-and 0/imm32/false
10889     75/jump-if-!= $maybe-define-var:end/disp8
10890     # otherwise update vars
10891     (push *(ebp+0x10) *(ebp+8))
10892     (push *(ebp+0x10) *(ebp+0xc))
10893     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
10894 $maybe-define-var:end:
10895     # . restore registers
10896     58/pop-to-eax
10897     # . epilogue
10898     89/<- %esp 5/r32/ebp
10899     5d/pop-to-ebp
10900     c3/return
10901 
10902 # simpler version of lookup-var-helper
10903 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
10904     # pseudocode:
10905     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
10906     #   var min = vars->data
10907     #   while curr >= min
10908     #     var v: (handle var) = *curr
10909     #     if v->name == target->name
10910     #       return true
10911     #     curr -= 12
10912     #   return false
10913     #
10914     # . prologue
10915     55/push-ebp
10916     89/<- %ebp 4/r32/esp
10917     # . save registers
10918     51/push-ecx
10919     52/push-edx
10920     56/push-esi
10921     # var target-name/ecx: (addr array byte) = lookup(target->name)
10922     8b/-> *(ebp+8) 0/r32/eax
10923     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10924     89/<- %ecx 0/r32/eax
10925     # esi = vars
10926     8b/-> *(ebp+0xc) 6/r32/esi
10927     # eax = vars->top
10928     8b/-> *esi 0/r32/eax
10929     # var min/edx: (addr handle var) = vars->data
10930     8d/copy-address *(esi+8) 2/r32/edx
10931     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10932     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
10933     {
10934 $binding-exists?:loop:
10935       # if (curr < min) return
10936       39/compare %esi 2/r32/edx
10937       0f 82/jump-if-addr< break/disp32
10938       # var v/eax: (addr var) = lookup(*curr)
10939       (lookup *esi *(esi+4))  # => eax
10940       # var vn/eax: (addr array byte) = lookup(v->name)
10941       (lookup *eax *(eax+4))  # Var-name Var-name => eax
10942       # if (vn == target-name) return true
10943       (string-equal? %ecx %eax)  # => eax
10944       3d/compare-eax-and 0/imm32/false
10945       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
10946       # curr -= 12
10947       81 5/subop/subtract %esi 0xc/imm32
10948       e9/jump loop/disp32
10949     }
10950     b8/copy-to-eax 0/imm32/false
10951 $binding-exists?:end:
10952     # . restore registers
10953     5e/pop-to-esi
10954     5a/pop-to-edx
10955     59/pop-to-ecx
10956     # . epilogue
10957     89/<- %esp 5/r32/ebp
10958     5d/pop-to-ebp
10959     c3/return
10960 
10961 test-parse-mu-stmt:
10962     # . prologue
10963     55/push-ebp
10964     89/<- %ebp 4/r32/esp
10965     # setup
10966     (clear-stream _test-input-stream)
10967     (write _test-input-stream "increment n\n")
10968     # var vars/ecx: (stack (addr var) 16)
10969     81 5/subop/subtract %esp 0xc0/imm32
10970     68/push 0xc0/imm32/size
10971     68/push 0/imm32/top
10972     89/<- %ecx 4/r32/esp
10973     (clear-stack %ecx)
10974     # var v/edx: (handle var)
10975     68/push 0/imm32
10976     68/push 0/imm32
10977     89/<- %edx 4/r32/esp
10978     # var s/eax: (handle array byte)
10979     68/push 0/imm32
10980     68/push 0/imm32
10981     89/<- %eax 4/r32/esp
10982     # v = new var("n")
10983     (copy-array Heap "n" %eax)
10984     (new-var Heap *eax *(eax+4) %edx)
10985     #
10986     (push %ecx *edx)
10987     (push %ecx *(edx+4))
10988     (push %ecx 0)
10989     # var out/eax: (handle stmt)
10990     68/push 0/imm32
10991     68/push 0/imm32
10992     89/<- %eax 4/r32/esp
10993     # convert
10994     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
10995     # var out-addr/edx: (addr stmt) = lookup(*out)
10996     (lookup *eax *(eax+4))  # => eax
10997     89/<- %edx 0/r32/eax
10998     # out->tag
10999     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
11000     # out->operation
11001     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
11002     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
11003     # out->inouts->value->name
11004     # . eax = out->inouts
11005     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11006     # . eax = out->inouts->value
11007     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11008     # . eax = out->inouts->value->name
11009     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11010     # .
11011     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
11012     # . epilogue
11013     89/<- %esp 5/r32/ebp
11014     5d/pop-to-ebp
11015     c3/return
11016 
11017 test-parse-mu-stmt-with-comma:
11018     # . prologue
11019     55/push-ebp
11020     89/<- %ebp 4/r32/esp
11021     # setup
11022     (clear-stream _test-input-stream)
11023     (write _test-input-stream "copy-to n, 3\n")
11024     # var vars/ecx: (stack (addr var) 16)
11025     81 5/subop/subtract %esp 0xc0/imm32
11026     68/push 0xc0/imm32/size
11027     68/push 0/imm32/top
11028     89/<- %ecx 4/r32/esp
11029     (clear-stack %ecx)
11030     # var v/edx: (handle var)
11031     68/push 0/imm32
11032     68/push 0/imm32
11033     89/<- %edx 4/r32/esp
11034     # var s/eax: (handle array byte)
11035     68/push 0/imm32
11036     68/push 0/imm32
11037     89/<- %eax 4/r32/esp
11038     # v = new var("n")
11039     (copy-array Heap "n" %eax)
11040     (new-var Heap *eax *(eax+4) %edx)
11041     #
11042     (push %ecx *edx)
11043     (push %ecx *(edx+4))
11044     (push %ecx 0)
11045     # var out/eax: (handle stmt)
11046     68/push 0/imm32
11047     68/push 0/imm32
11048     89/<- %eax 4/r32/esp
11049     # convert
11050     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
11051     # var out-addr/edx: (addr stmt) = lookup(*out)
11052     (lookup *eax *(eax+4))  # => eax
11053     89/<- %edx 0/r32/eax
11054     # out->tag
11055     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
11056     # out->operation
11057     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
11058     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
11059     # out->inouts->value->name
11060     # . eax = out->inouts
11061     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11062     # . eax = out->inouts->value
11063     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11064     # . eax = out->inouts->value->name
11065     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11066     # .
11067     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
11068     # . epilogue
11069     89/<- %esp 5/r32/ebp
11070     5d/pop-to-ebp
11071     c3/return
11072 
11073 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
11074     # . prologue
11075     55/push-ebp
11076     89/<- %ebp 4/r32/esp
11077     # . save registers
11078     50/push-eax
11079     51/push-ecx
11080     # ecx = out
11081     8b/-> *(ebp+0x14) 1/r32/ecx
11082     #
11083     (allocate *(ebp+8) *Var-size %ecx)
11084     # var out-addr/eax: (addr var)
11085     (lookup *ecx *(ecx+4))  # => eax
11086     # out-addr->name = name
11087     8b/-> *(ebp+0xc) 1/r32/ecx
11088     89/<- *eax 1/r32/ecx  # Var-name
11089     8b/-> *(ebp+0x10) 1/r32/ecx
11090     89/<- *(eax+4) 1/r32/ecx  # Var-name
11091 #?     (write-buffered Stderr "var ")
11092 #?     (lookup *(ebp+0xc) *(ebp+0x10))
11093 #?     (write-buffered Stderr %eax)
11094 #?     (write-buffered Stderr " at ")
11095 #?     8b/-> *(ebp+0x14) 1/r32/ecx
11096 #?     (lookup *ecx *(ecx+4))  # => eax
11097 #?     (write-int32-hex-buffered Stderr %eax)
11098 #?     (write-buffered Stderr Newline)
11099 #?     (flush Stderr)
11100 $new-var:end:
11101     # . restore registers
11102     59/pop-to-ecx
11103     58/pop-to-eax
11104     # . epilogue
11105     89/<- %esp 5/r32/ebp
11106     5d/pop-to-ebp
11107     c3/return
11108 
11109 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)
11110     # . prologue
11111     55/push-ebp
11112     89/<- %ebp 4/r32/esp
11113     # . save registers
11114     50/push-eax
11115     51/push-ecx
11116     # if (!is-hex-int?(name)) abort
11117     (is-hex-int? *(ebp+0xc))  # => eax
11118     3d/compare-eax-and 0/imm32/false
11119     0f 84/jump-if-= $new-literal-integer:abort/disp32
11120     # a little more error-checking
11121     (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
11122     # out = new var(s)
11123     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
11124     # var out-addr/ecx: (addr var) = lookup(*out)
11125     8b/-> *(ebp+0x10) 0/r32/eax
11126     (lookup *eax *(eax+4))  # => eax
11127     89/<- %ecx 0/r32/eax
11128     # out-addr->block-depth = *Curr-block-depth
11129     8b/-> *Curr-block-depth 0/r32/eax
11130     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11131     # out-addr->type = new tree()
11132     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11133     (allocate *(ebp+8) *Type-tree-size %eax)
11134     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11135     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11136     # nothing else to do; default type is 'literal'
11137 $new-literal-integer:end:
11138     # . reclaim locals
11139     81 0/subop/add %esp 8/imm32
11140     # . restore registers
11141     59/pop-to-ecx
11142     58/pop-to-eax
11143     # . epilogue
11144     89/<- %esp 5/r32/ebp
11145     5d/pop-to-ebp
11146     c3/return
11147 
11148 $new-literal-integer:abort:
11149     (write-buffered *(ebp+0x18) "fn ")
11150     8b/-> *(ebp+0x14) 0/r32/eax
11151     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11152     (write-buffered *(ebp+0x18) %eax)
11153     (write-buffered *(ebp+0x18) ": variable '")
11154     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
11155     (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
11156     (flush *(ebp+0x18))
11157     (stop *(ebp+0x1c) 1)
11158     # never gets here
11159 
11160 # precondition: name is a valid hex integer; require a '0x' prefix
11161 check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
11162     # . prologue
11163     55/push-ebp
11164     89/<- %ebp 4/r32/esp
11165     # . save registers
11166     50/push-eax
11167     51/push-ecx
11168     52/push-edx
11169     # ecx = name
11170     8b/-> *(ebp+8) 1/r32/ecx
11171     # var start/edx: (addr byte) = name->start
11172     8b/-> *ecx 2/r32/edx
11173     # if (*start == '-') ++start
11174     b8/copy-to-eax 0/imm32
11175     8a/copy-byte *edx 0/r32/AL
11176     3d/compare-eax-and 0x2d/imm32/dash
11177     {
11178       75/jump-if-!= break/disp8
11179       42/increment-edx
11180     }
11181     # var end/ecx: (addr byte) = name->end
11182     8b/-> *(ecx+4) 1/r32/ecx
11183     # var len/eax: int = name->end - name->start
11184     89/<- %eax 1/r32/ecx
11185     29/subtract-from %eax 2/r32/edx
11186     # if (len <= 1) return
11187     3d/compare-eax-with 1/imm32
11188     0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
11189 $check-mu-hex-int:length->-1:
11190     # if slice-starts-with?({start, end}, "0x") return
11191     # . var tmp = {start, end}
11192     51/push-ecx
11193     52/push-edx
11194     89/<- %eax 4/r32/esp
11195     # .
11196     (slice-starts-with? %eax "0x")  # => eax
11197     # . reclaim tmp
11198     81 0/subop/add %esp 8/imm32
11199     # .
11200     3d/compare-eax-with 0/imm32/false
11201     75/jump-if-!= $check-mu-hex-int:end/disp8
11202 $check-mu-hex-int:abort:
11203     # otherwise abort
11204     (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
11205     (write-slice-buffered *(ebp+0xc) *(ebp+8))
11206     (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
11207     (flush *(ebp+0xc))
11208     (stop *(ebp+0x10) 1)
11209 $check-mu-hex-int:end:
11210     # . restore registers
11211     5a/pop-to-edx
11212     59/pop-to-ecx
11213     58/pop-to-eax
11214     # . epilogue
11215     89/<- %esp 5/r32/ebp
11216     5d/pop-to-ebp
11217     c3/return
11218 
11219 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11220     # . prologue
11221     55/push-ebp
11222     89/<- %ebp 4/r32/esp
11223     # . save registers
11224     50/push-eax
11225     51/push-ecx
11226     # var s/ecx: (handle array byte)
11227     68/push 0/imm32
11228     68/push 0/imm32
11229     89/<- %ecx 4/r32/esp
11230     # s = slice-to-string(name)
11231     (slice-to-string Heap *(ebp+0xc) %ecx)
11232     # allocate to out
11233     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11234     # var out-addr/ecx: (addr var) = lookup(*out)
11235     8b/-> *(ebp+0x10) 1/r32/ecx
11236     (lookup *ecx *(ecx+4))  # => eax
11237     89/<- %ecx 0/r32/eax
11238     # out-addr->block-depth = *Curr-block-depth
11239     8b/-> *Curr-block-depth 0/r32/eax
11240     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11241     # out-addr->type/eax = new type
11242     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
11243     (allocate *(ebp+8) *Type-tree-size %eax)
11244     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11245     # nothing else to do; default type is 'literal'
11246     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11247 $new-literal:end:
11248     # . reclaim locals
11249     81 0/subop/add %esp 8/imm32
11250     # . restore registers
11251     59/pop-to-ecx
11252     58/pop-to-eax
11253     # . epilogue
11254     89/<- %esp 5/r32/ebp
11255     5d/pop-to-ebp
11256     c3/return
11257 
11258 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
11259     # . prologue
11260     55/push-ebp
11261     89/<- %ebp 4/r32/esp
11262     # . save registers
11263     51/push-ecx
11264     # var tmp/ecx: (handle array byte)
11265     68/push 0/imm32
11266     68/push 0/imm32
11267     89/<- %ecx 4/r32/esp
11268     # tmp = slice-to-string(name)
11269     (slice-to-string Heap *(ebp+0xc) %ecx)
11270     # out = new-var(tmp)
11271     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
11272 $new-var-from-slice:end:
11273     # . reclaim locals
11274     81 0/subop/add %esp 8/imm32
11275     # . restore registers
11276     59/pop-to-ecx
11277     # . epilogue
11278     89/<- %esp 5/r32/ebp
11279     5d/pop-to-ebp
11280     c3/return
11281 
11282 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11283     # . prologue
11284     55/push-ebp
11285     89/<- %ebp 4/r32/esp
11286     # . save registers
11287     50/push-eax
11288     51/push-ecx
11289     #
11290     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
11291     # var out-addr/eax: (addr stmt) = lookup(*out)
11292     8b/-> *(ebp+0x14) 0/r32/eax
11293     (lookup *eax *(eax+4))  # => eax
11294     # out-addr->tag = stmt
11295     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
11296     # result->var = var
11297     8b/-> *(ebp+0xc) 1/r32/ecx
11298     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
11299     8b/-> *(ebp+0x10) 1/r32/ecx
11300     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
11301 $new-var-def:end:
11302     # . restore registers
11303     59/pop-to-ecx
11304     58/pop-to-eax
11305     # . epilogue
11306     89/<- %esp 5/r32/ebp
11307     5d/pop-to-ebp
11308     c3/return
11309 
11310 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
11311     # . prologue
11312     55/push-ebp
11313     89/<- %ebp 4/r32/esp
11314     # . save registers
11315     50/push-eax
11316     # eax = out
11317     8b/-> *(ebp+0x14) 0/r32/eax
11318     #
11319     (allocate *(ebp+8) *Stmt-size %eax)
11320     # var out-addr/eax: (addr stmt) = lookup(*out)
11321     (lookup *eax *(eax+4))  # => eax
11322     # set tag
11323     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
11324     # set output
11325     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
11326     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
11327 $new-reg-var-def:end:
11328     # . restore registers
11329     58/pop-to-eax
11330     # . epilogue
11331     89/<- %esp 5/r32/ebp
11332     5d/pop-to-ebp
11333     c3/return
11334 
11335 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
11336     # . prologue
11337     55/push-ebp
11338     89/<- %ebp 4/r32/esp
11339     # . save registers
11340     50/push-eax
11341     51/push-ecx
11342     57/push-edi
11343     # edi = out
11344     8b/-> *(ebp+0x1c) 7/r32/edi
11345     # *out = new list
11346     (allocate *(ebp+8) *List-size %edi)
11347     # var out-addr/edi: (addr list _type) = lookup(*out)
11348     (lookup *edi *(edi+4))  # => eax
11349     89/<- %edi 0/r32/eax
11350     # out-addr->value = value
11351     8b/-> *(ebp+0xc) 0/r32/eax
11352     89/<- *edi 0/r32/eax  # List-value
11353     8b/-> *(ebp+0x10) 0/r32/eax
11354     89/<- *(edi+4) 0/r32/eax  # List-value
11355     # if (list == null) return
11356     81 7/subop/compare *(ebp+0x14) 0/imm32
11357     74/jump-if-= $append-list:end/disp8
11358     # otherwise append
11359 $append-list:non-empty-list:
11360     # var curr/eax: (addr list _type) = lookup(list)
11361     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11362     # while (curr->next != null) curr = curr->next
11363     {
11364       81 7/subop/compare *(eax+8) 0/imm32  # List-next
11365       74/jump-if-= break/disp8
11366       # curr = lookup(curr->next)
11367       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
11368       #
11369       eb/jump loop/disp8
11370     }
11371     # edi = out
11372     8b/-> *(ebp+0x1c) 7/r32/edi
11373     # curr->next = out
11374     8b/-> *edi 1/r32/ecx
11375     89/<- *(eax+8) 1/r32/ecx  # List-next
11376     8b/-> *(edi+4) 1/r32/ecx
11377     89/<- *(eax+0xc) 1/r32/ecx  # List-next
11378     # out = list
11379     8b/-> *(ebp+0x14) 1/r32/ecx
11380     89/<- *edi 1/r32/ecx
11381     8b/-> *(ebp+0x18) 1/r32/ecx
11382     89/<- *(edi+4) 1/r32/ecx
11383 $append-list:end:
11384     # . restore registers
11385     5f/pop-to-edi
11386     59/pop-to-ecx
11387     58/pop-to-eax
11388     # . epilogue
11389     89/<- %esp 5/r32/ebp
11390     5d/pop-to-ebp
11391     c3/return
11392 
11393 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
11394     # . prologue
11395     55/push-ebp
11396     89/<- %ebp 4/r32/esp
11397     # . save registers
11398     50/push-eax
11399     51/push-ecx
11400     57/push-edi
11401     # edi = out
11402     8b/-> *(ebp+0x20) 7/r32/edi
11403     # out = new stmt-var
11404     (allocate *(ebp+8) *Stmt-var-size %edi)
11405     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
11406     (lookup *edi *(edi+4))  # => eax
11407     89/<- %ecx 0/r32/eax
11408     # out-addr->value = v
11409     8b/-> *(ebp+0xc) 0/r32/eax
11410     89/<- *ecx 0/r32/eax  # Stmt-var-value
11411     8b/-> *(ebp+0x10) 0/r32/eax
11412     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
11413     # out-addr->is-deref? = is-deref?
11414     8b/-> *(ebp+0x1c) 0/r32/eax
11415     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
11416     # if (vars == null) return result
11417     81 7/subop/compare *(ebp+0x14) 0/imm32/null
11418     74/jump-if-= $append-stmt-var:end/disp8
11419     # otherwise append
11420     # var curr/eax: (addr stmt-var) = lookup(vars)
11421     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
11422     # while (curr->next != null) curr = curr->next
11423     {
11424       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11425       74/jump-if-= break/disp8
11426       # curr = lookup(curr->next)
11427       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
11428       #
11429       eb/jump loop/disp8
11430     }
11431     # curr->next = out
11432     8b/-> *edi 1/r32/ecx
11433     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
11434     8b/-> *(edi+4) 1/r32/ecx
11435     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
11436     # out = vars
11437     8b/-> *(ebp+0x14) 1/r32/ecx
11438     89/<- *edi 1/r32/ecx
11439     8b/-> *(ebp+0x18) 1/r32/ecx
11440     89/<- *(edi+4) 1/r32/ecx
11441 $append-stmt-var:end:
11442     # . restore registers
11443     5f/pop-to-edi
11444     59/pop-to-ecx
11445     58/pop-to-eax
11446     # . epilogue
11447     89/<- %esp 5/r32/ebp
11448     5d/pop-to-ebp
11449     c3/return
11450 
11451 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
11452     # . prologue
11453     55/push-ebp
11454     89/<- %ebp 4/r32/esp
11455     # . save registers
11456     50/push-eax
11457     56/push-esi
11458     # esi = block
11459     8b/-> *(ebp+0xc) 6/r32/esi
11460     # block->stmts = append(x, block->stmts)
11461     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
11462     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
11463 $append-to-block:end:
11464     # . restore registers
11465     5e/pop-to-esi
11466     58/pop-to-eax
11467     # . epilogue
11468     89/<- %esp 5/r32/ebp
11469     5d/pop-to-ebp
11470     c3/return
11471 
11472 ## Parsing types
11473 # We need to create metadata on user-defined types, and we need to use this
11474 # metadata as we parse instructions.
11475 # However, we also want to allow types to be used before their definitions.
11476 # This means we can't ever assume any type data structures exist.
11477 
11478 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
11479     # . prologue
11480     55/push-ebp
11481     89/<- %ebp 4/r32/esp
11482     # . save registers
11483     50/push-eax
11484     56/push-esi
11485     # var container-type/esi: type-id
11486     (container-type *(ebp+8))  # => eax
11487     89/<- %esi 0/r32/eax
11488     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
11489     68/push 0/imm32
11490     68/push 0/imm32
11491     89/<- %eax 4/r32/esp
11492     (find-or-create-typeinfo %esi %eax)
11493     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
11494     (lookup *eax *(eax+4))  # => eax
11495     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
11496 #?     (write-buffered Stderr "constant: ")
11497 #?     (write-slice-buffered Stderr *(ebp+0xc))
11498 #?     (write-buffered Stderr Newline)
11499 #?     (flush Stderr)
11500     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
11501 #?     8b/-> *(ebp+0x10) 0/r32/eax
11502 #?     (write-buffered Stderr "@")
11503 #?     (lookup *eax *(eax+4))
11504 #?     (write-int32-hex-buffered Stderr %eax)
11505 #?     (lookup *eax *(eax+4))
11506 #?     (write-buffered Stderr %eax)
11507 #?     (write-buffered Stderr Newline)
11508 #?     (flush Stderr)
11509 #?     (write-buffered Stderr "offset: ")
11510 #?     8b/-> *(eax+0x14) 0/r32/eax
11511 #?     (write-int32-hex-buffered Stderr %eax)
11512 #?     (write-buffered Stderr Newline)
11513 #?     (flush Stderr)
11514 $lookup-or-create-constant:end:
11515     # . reclaim locals
11516     81 0/subop/add %esp 8/imm32
11517     # . restore registers
11518     5e/pop-to-esi
11519     58/pop-to-eax
11520     # . epilogue
11521     89/<- %esp 5/r32/ebp
11522     5d/pop-to-ebp
11523     c3/return
11524 
11525 # if addr var:
11526 #   container->var->type->right->left->value
11527 # otherwise
11528 #   container->var->type->value
11529 container-type:  # container: (addr stmt-var) -> result/eax: type-id
11530     # . prologue
11531     55/push-ebp
11532     89/<- %ebp 4/r32/esp
11533     #
11534     8b/-> *(ebp+8) 0/r32/eax
11535     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11536     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11537     {
11538       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
11539       74/jump-if-= break/disp8
11540       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
11541       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11542     }
11543     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
11544 $container-type:end:
11545     # . epilogue
11546     89/<- %esp 5/r32/ebp
11547     5d/pop-to-ebp
11548     c3/return
11549 
11550 is-container?:  # t: type-id -> result/eax: boolean
11551     # . prologue
11552     55/push-ebp
11553     89/<- %ebp 4/r32/esp
11554     #
11555     8b/-> *(ebp+8) 0/r32/eax
11556     c1/shift 4/subop/left %eax 2/imm8
11557     3b/compare 0/r32/eax *Primitive-type-ids
11558     0f 9d/set-if->= %al
11559     81 4/subop/and %eax 0xff/imm32
11560 $is-container?:end:
11561     # . epilogue
11562     89/<- %esp 5/r32/ebp
11563     5d/pop-to-ebp
11564     c3/return
11565 
11566 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11567     # . prologue
11568     55/push-ebp
11569     89/<- %ebp 4/r32/esp
11570     # . save registers
11571     50/push-eax
11572     51/push-ecx
11573     52/push-edx
11574     57/push-edi
11575     # edi = out
11576     8b/-> *(ebp+0xc) 7/r32/edi
11577     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
11578     68/push 0/imm32
11579     68/push 0/imm32
11580     89/<- %ecx 4/r32/esp
11581     # find-typeinfo(t, out)
11582     (find-typeinfo *(ebp+8) %edi)
11583     {
11584       # if (*out != 0) break
11585       81 7/subop/compare *edi 0/imm32
11586       0f 85/jump-if-!= break/disp32
11587 $find-or-create-typeinfo:create:
11588       # *out = allocate
11589       (allocate Heap *Typeinfo-size %edi)
11590       # var tmp/eax: (addr typeinfo) = lookup(*out)
11591       (lookup *edi *(edi+4))  # => eax
11592 #?     (write-buffered Stderr "created typeinfo at ")
11593 #?     (write-int32-hex-buffered Stderr %eax)
11594 #?     (write-buffered Stderr " for type-id ")
11595 #?     (write-int32-hex-buffered Stderr *(ebp+8))
11596 #?     (write-buffered Stderr Newline)
11597 #?     (flush Stderr)
11598       # tmp->id = t
11599       8b/-> *(ebp+8) 2/r32/edx
11600       89/<- *eax 2/r32/edx  # Typeinfo-id
11601       # tmp->fields = new table
11602       # . fields = new table
11603       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
11604       # . tmp->fields = fields
11605       8b/-> *ecx 2/r32/edx
11606       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
11607       8b/-> *(ecx+4) 2/r32/edx
11608       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
11609       # tmp->next = Program->types
11610       8b/-> *_Program-types 1/r32/ecx
11611       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
11612       8b/-> *_Program-types->payload 1/r32/ecx
11613       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
11614       # Program->types = out
11615       8b/-> *edi 1/r32/ecx
11616       89/<- *_Program-types 1/r32/ecx
11617       8b/-> *(edi+4) 1/r32/ecx
11618       89/<- *_Program-types->payload 1/r32/ecx
11619     }
11620 $find-or-create-typeinfo:end:
11621     # . reclaim locals
11622     81 0/subop/add %esp 8/imm32
11623     # . restore registers
11624     5f/pop-to-edi
11625     5a/pop-to-edx
11626     59/pop-to-ecx
11627     58/pop-to-eax
11628     # . epilogue
11629     89/<- %esp 5/r32/ebp
11630     5d/pop-to-ebp
11631     c3/return
11632 
11633 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
11634     # . prologue
11635     55/push-ebp
11636     89/<- %ebp 4/r32/esp
11637     # . save registers
11638     50/push-eax
11639     51/push-ecx
11640     52/push-edx
11641     57/push-edi
11642     # ecx = t
11643     8b/-> *(ebp+8) 1/r32/ecx
11644     # edi = out
11645     8b/-> *(ebp+0xc) 7/r32/edi
11646     # *out = Program->types
11647     8b/-> *_Program-types 0/r32/eax
11648     89/<- *edi 0/r32/eax
11649     8b/-> *_Program-types->payload 0/r32/eax
11650     89/<- *(edi+4) 0/r32/eax
11651     {
11652 $find-typeinfo:loop:
11653       # if (*out == 0) break
11654       81 7/subop/compare *edi 0/imm32
11655       74/jump-if-= break/disp8
11656 $find-typeinfo:check:
11657       # var tmp/eax: (addr typeinfo) = lookup(*out)
11658       (lookup *edi *(edi+4))  # => eax
11659       # if (tmp->id == t) break
11660       39/compare *eax 1/r32/ecx  # Typeinfo-id
11661       74/jump-if-= break/disp8
11662 $find-typeinfo:continue:
11663       # *out = tmp->next
11664       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
11665       89/<- *edi 2/r32/edx
11666       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
11667       89/<- *(edi+4) 2/r32/edx
11668       #
11669       eb/jump loop/disp8
11670     }
11671 $find-typeinfo:end:
11672     # . restore registers
11673     5f/pop-to-edi
11674     5a/pop-to-edx
11675     59/pop-to-ecx
11676     58/pop-to-eax
11677     # . epilogue
11678     89/<- %esp 5/r32/ebp
11679     5d/pop-to-ebp
11680     c3/return
11681 
11682 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
11683     # . prologue
11684     55/push-ebp
11685     89/<- %ebp 4/r32/esp
11686     # . save registers
11687     50/push-eax
11688     52/push-edx
11689     57/push-edi
11690     # var dest/edi: (handle typeinfo-entry)
11691     68/push 0/imm32
11692     68/push 0/imm32
11693     89/<- %edi 4/r32/esp
11694     # find-or-create-typeinfo-fields(T, f, dest)
11695     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
11696     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
11697     (lookup *edi *(edi+4))  # => eax
11698     89/<- %edi 0/r32/eax
11699     # if dest-addr->output-var doesn't exist, create it
11700     {
11701       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
11702       0f 85/jump-if-!= break/disp32
11703       # dest-addr->output-var = new var(dummy name, type, -1 offset)
11704       # . var name/eax: (handle array byte) = "field"
11705       68/push 0/imm32
11706       68/push 0/imm32
11707       89/<- %eax 4/r32/esp
11708       (slice-to-string Heap *(ebp+0xc) %eax)
11709       # . new var
11710       8d/copy-address *(edi+0xc) 2/r32/edx
11711       (new-var Heap  *eax *(eax+4)  %edx)
11712       # . reclaim name
11713       81 0/subop/add %esp 8/imm32
11714       # var result/edx: (addr var) = lookup(dest-addr->output-var)
11715       (lookup *(edi+0xc) *(edi+0x10))  # => eax
11716       89/<- %edx 0/r32/eax
11717       # result->type = new constant type
11718       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
11719       (allocate Heap *Type-tree-size %eax)
11720       (lookup *(edx+8) *(edx+0xc))  # => eax
11721       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
11722       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
11723       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
11724       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
11725       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
11726       # result->offset isn't filled out yet
11727       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
11728     }
11729     # out = dest-addr->output-var
11730     8b/-> *(ebp+0x10) 2/r32/edx
11731     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11732     89/<- *edx 0/r32/eax
11733     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
11734     89/<- *(edx+4) 0/r32/eax
11735 $find-or-create-typeinfo-output-var:end:
11736     # . reclaim locals
11737     81 0/subop/add %esp 8/imm32
11738     # . restore registers
11739     5f/pop-to-edi
11740     5a/pop-to-edx
11741     58/pop-to-eax
11742     # . epilogue
11743     89/<- %esp 5/r32/ebp
11744     5d/pop-to-ebp
11745     c3/return
11746 
11747 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
11748     # . prologue
11749     55/push-ebp
11750     89/<- %ebp 4/r32/esp
11751     # . save registers
11752     50/push-eax
11753     56/push-esi
11754     57/push-edi
11755     # eax = lookup(T->fields)
11756     8b/-> *(ebp+8) 0/r32/eax
11757     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
11758     # edi = out
11759     8b/-> *(ebp+0x10) 7/r32/edi
11760     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
11761     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
11762     89/<- %esi 0/r32/eax
11763     # if src doesn't exist, allocate it
11764     {
11765       81 7/subop/compare *esi 0/imm32
11766       75/jump-if-!= break/disp8
11767       (allocate Heap *Typeinfo-entry-size %esi)
11768 #?       (write-buffered Stderr "handle at ")
11769 #?       (write-int32-hex-buffered Stderr %esi)
11770 #?       (write-buffered Stderr ": ")
11771 #?       (write-int32-hex-buffered Stderr *esi)
11772 #?       (write-buffered Stderr " ")
11773 #?       (write-int32-hex-buffered Stderr *(esi+4))
11774 #?       (write-buffered Stderr Newline)
11775 #?       (flush Stderr)
11776 #?       (lookup *esi *(esi+4))
11777 #?       (write-buffered Stderr "created typeinfo fields at ")
11778 #?       (write-int32-hex-buffered Stderr %esi)
11779 #?       (write-buffered Stderr " for ")
11780 #?       (write-int32-hex-buffered Stderr *(ebp+8))
11781 #?       (write-buffered Stderr Newline)
11782 #?       (flush Stderr)
11783     }
11784     # *out = src
11785     # . *edi = *src
11786     8b/-> *esi 0/r32/eax
11787     89/<- *edi 0/r32/eax
11788     8b/-> *(esi+4) 0/r32/eax
11789     89/<- *(edi+4) 0/r32/eax
11790 $find-or-create-typeinfo-fields:end:
11791     # . restore registers
11792     5f/pop-to-edi
11793     5e/pop-to-esi
11794     58/pop-to-eax
11795     # . epilogue
11796     89/<- %esp 5/r32/ebp
11797     5d/pop-to-ebp
11798     c3/return
11799 
11800 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
11801     # pseudocode:
11802     #   var line: (stream byte 512)
11803     #   curr-index = 0
11804     #   while true
11805     #     clear-stream(line)
11806     #     read-line-buffered(in, line)
11807     #     if line->write == 0
11808     #       abort
11809     #     word-slice = next-mu-token(line)
11810     #     if slice-empty?(word-slice)               # end of line
11811     #       continue
11812     #     if slice-equal?(word-slice, "}")
11813     #       break
11814     #     var v: (handle var) = parse-var-with-type(word-slice, line)
11815     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
11816     #     TODO: ensure that r->first is null
11817     #     r->index = curr-index
11818     #     curr-index++
11819     #     r->input-var = v
11820     #     if r->output-var == 0
11821     #       r->output-var = new literal
11822     #     TODO: ensure nothing else in line
11823     # t->total-size-in-bytes = -2 (not yet initialized)
11824     #
11825     # . prologue
11826     55/push-ebp
11827     89/<- %ebp 4/r32/esp
11828     # var curr-index: int at *(ebp-4)
11829     68/push 0/imm32
11830     # . save registers
11831     50/push-eax
11832     51/push-ecx
11833     52/push-edx
11834     53/push-ebx
11835     56/push-esi
11836     57/push-edi
11837     # edi = t
11838     8b/-> *(ebp+0xc) 7/r32/edi
11839     # var line/ecx: (stream byte 512)
11840     81 5/subop/subtract %esp 0x200/imm32
11841     68/push 0x200/imm32/size
11842     68/push 0/imm32/read
11843     68/push 0/imm32/write
11844     89/<- %ecx 4/r32/esp
11845     # var word-slice/edx: slice
11846     68/push 0/imm32/end
11847     68/push 0/imm32/start
11848     89/<- %edx 4/r32/esp
11849     # var v/esi: (handle var)
11850     68/push 0/imm32
11851     68/push 0/imm32
11852     89/<- %esi 4/r32/esp
11853     # var r/ebx: (handle typeinfo-entry)
11854     68/push 0/imm32
11855     68/push 0/imm32
11856     89/<- %ebx 4/r32/esp
11857     {
11858 $populate-mu-type:line-loop:
11859       (clear-stream %ecx)
11860       (read-line-buffered *(ebp+8) %ecx)
11861       # if (line->write == 0) abort
11862       81 7/subop/compare *ecx 0/imm32
11863       0f 84/jump-if-= $populate-mu-type:error1/disp32
11864 +--  6 lines: #?       # dump line ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11870       (next-mu-token %ecx %edx)
11871       # if slice-empty?(word-slice) continue
11872       (slice-empty? %edx)  # => eax
11873       3d/compare-eax-and 0/imm32
11874       0f 85/jump-if-!= loop/disp32
11875       # if slice-equal?(word-slice, "}") break
11876       (slice-equal? %edx "}")
11877       3d/compare-eax-and 0/imm32
11878       0f 85/jump-if-!= break/disp32
11879 $populate-mu-type:parse-element:
11880       # v = parse-var-with-type(word-slice, first-line)
11881       # must do this first to strip the trailing ':' from word-slice before
11882       # using it in find-or-create-typeinfo-fields below
11883       # TODO: clean up that mutation in parse-var-with-type
11884       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
11885       # if v is an addr, abort
11886       (lookup *esi *(esi+4))  # => eax
11887       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11888       (is-mu-addr-type? %eax)  # => eax
11889       3d/compare-eax-and 0/imm32/false
11890       0f 85/jump-if-!= $populate-mu-type:error2/disp32
11891       # if v is an array, abort  (we could support it, but initialization gets complex)
11892       (lookup *esi *(esi+4))  # => eax
11893       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11894       (is-mu-array-type? %eax)  # => eax
11895       3d/compare-eax-and 0/imm32/false
11896       0f 85/jump-if-!= $populate-mu-type:error3/disp32
11897       # if v is a byte, abort
11898       (lookup *esi *(esi+4))  # => eax
11899       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11900       (is-simple-mu-type? %eax 8)  # byte => eax
11901       3d/compare-eax-and 0/imm32/false
11902       0f 85/jump-if-!= $populate-mu-type:error4/disp32
11903       # if v is a slice, abort
11904       (lookup *esi *(esi+4))  # => eax
11905       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11906       (is-simple-mu-type? %eax 0xc)  # slice => eax
11907       3d/compare-eax-and 0/imm32/false
11908       0f 85/jump-if-!= $populate-mu-type:error5/disp32
11909       # if v is a stream, abort  (we could support it, but initialization gets even more complex)
11910       (lookup *esi *(esi+4))  # => eax
11911       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11912       (is-mu-stream-type? %eax)  # => eax
11913       3d/compare-eax-and 0/imm32/false
11914       0f 85/jump-if-!= $populate-mu-type:error6/disp32
11915       # var tmp/ecx
11916       51/push-ecx
11917 $populate-mu-type:create-typeinfo-fields:
11918       # var r/ebx: (handle typeinfo-entry)
11919       (find-or-create-typeinfo-fields %edi %edx %ebx)
11920       # r->index = curr-index
11921       (lookup *ebx *(ebx+4))  # => eax
11922       8b/-> *(ebp-4) 1/r32/ecx
11923 #?       (write-buffered Stderr "saving index ")
11924 #?       (write-int32-hex-buffered Stderr %ecx)
11925 #?       (write-buffered Stderr " at ")
11926 #?       (write-int32-hex-buffered Stderr %edi)
11927 #?       (write-buffered Stderr Newline)
11928 #?       (flush Stderr)
11929       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
11930       # ++curr-index
11931       ff 0/subop/increment *(ebp-4)
11932 $populate-mu-type:set-input-type:
11933       # r->input-var = v
11934       8b/-> *esi 1/r32/ecx
11935       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
11936       8b/-> *(esi+4) 1/r32/ecx
11937       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
11938       # restore line
11939       59/pop-to-ecx
11940       {
11941 $populate-mu-type:create-output-type:
11942         # if (r->output-var == 0) create a new var with some placeholder data
11943         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
11944         75/jump-if-!= break/disp8
11945         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
11946         (new-literal Heap %edx %eax)
11947       }
11948       e9/jump loop/disp32
11949     }
11950 $populate-mu-type:invalidate-total-size-in-bytes:
11951     # Offsets and total size may not be accurate here since we may not yet
11952     # have encountered the element types.
11953     # We'll recompute them separately after parsing the entire program.
11954     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
11955 $populate-mu-type:end:
11956     # . reclaim locals
11957     81 0/subop/add %esp 0x224/imm32
11958     # . restore registers
11959     5f/pop-to-edi
11960     5e/pop-to-esi
11961     5b/pop-to-ebx
11962     5a/pop-to-edx
11963     59/pop-to-ecx
11964     58/pop-to-eax
11965     # reclaim curr-index
11966     81 0/subop/add %esp 4/imm32
11967     # . epilogue
11968     89/<- %esp 5/r32/ebp
11969     5d/pop-to-ebp
11970     c3/return
11971 
11972 $populate-mu-type:error1:
11973     # error("incomplete type definition '" t->name "'\n")
11974     (write-buffered *(ebp+0x10) "incomplete type definition '")
11975     (type-name *edi)  # Typeinfo-id => eax
11976     (write-buffered *(ebp+0x10) %eax)
11977     (write-buffered *(ebp+0x10) "\n")
11978     (flush *(ebp+0x10))
11979     (stop *(ebp+0x14) 1)
11980     # never gets here
11981 
11982 $populate-mu-type:error2:
11983     (write-buffered *(ebp+0x10) "type ")
11984     (type-name *edi)  # Typeinfo-id => eax
11985     (write-buffered *(ebp+0x10) %eax)
11986     (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
11987     (flush *(ebp+0x10))
11988     (stop *(ebp+0x14) 1)
11989     # never gets here
11990 
11991 $populate-mu-type:error3:
11992     (write-buffered *(ebp+0x10) "type ")
11993     (type-name *edi)  # Typeinfo-id => eax
11994     (write-buffered *(ebp+0x10) %eax)
11995     (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
11996     (flush *(ebp+0x10))
11997     (stop *(ebp+0x14) 1)
11998     # never gets here
11999 
12000 $populate-mu-type:error4:
12001     (write-buffered *(ebp+0x10) "type ")
12002     (type-name *edi)  # Typeinfo-id => eax
12003     (write-buffered *(ebp+0x10) %eax)
12004     (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
12005     (flush *(ebp+0x10))
12006     (stop *(ebp+0x14) 1)
12007     # never gets here
12008 
12009 $populate-mu-type:error5:
12010     (write-buffered *(ebp+0x10) "type ")
12011     (type-name *edi)  # Typeinfo-id => eax
12012     (write-buffered *(ebp+0x10) %eax)
12013     (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
12014     (flush *(ebp+0x10))
12015     (stop *(ebp+0x14) 1)
12016     # never gets here
12017 
12018 $populate-mu-type:error6:
12019     (write-buffered *(ebp+0x10) "type ")
12020     (type-name *edi)  # Typeinfo-id => eax
12021     (write-buffered *(ebp+0x10) %eax)
12022     (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
12023     (flush *(ebp+0x10))
12024     (stop *(ebp+0x14) 1)
12025     # never gets here
12026 
12027 type-name:  # index: int -> result/eax: (addr array byte)
12028     # . prologue
12029     55/push-ebp
12030     89/<- %ebp 4/r32/esp
12031     #
12032     (index Type-id *(ebp+8))
12033 $type-name:end:
12034     # . epilogue
12035     89/<- %esp 5/r32/ebp
12036     5d/pop-to-ebp
12037     c3/return
12038 
12039 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
12040     # . prologue
12041     55/push-ebp
12042     89/<- %ebp 4/r32/esp
12043     # . save registers
12044     56/push-esi
12045     # TODO: bounds-check index
12046     # esi = arr
12047     8b/-> *(ebp+8) 6/r32/esi
12048     # eax = index
12049     8b/-> *(ebp+0xc) 0/r32/eax
12050     # eax = *(arr + 12 + index)
12051     8b/-> *(esi+eax<<2+0xc) 0/r32/eax
12052 $index:end:
12053     # . restore registers
12054     5e/pop-to-esi
12055     # . epilogue
12056     89/<- %esp 5/r32/ebp
12057     5d/pop-to-ebp
12058     c3/return
12059 
12060 #######################################################
12061 # Compute type sizes
12062 #######################################################
12063 
12064 # Compute the sizes of all user-defined types.
12065 # We'll need the sizes of their elements, which may be other user-defined
12066 # types, which we will compute as needed.
12067 
12068 # Initially, all user-defined types have their sizes set to -2 (invalid)
12069 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12070     # . prologue
12071     55/push-ebp
12072     89/<- %ebp 4/r32/esp
12073 $populate-mu-type-sizes:total-sizes:
12074     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12075     (lookup *_Program-types *_Program-types->payload)  # => eax
12076     {
12077       # if (curr == null) break
12078       3d/compare-eax-and 0/imm32/null
12079       74/jump-if-= break/disp8
12080       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
12081       # curr = lookup(curr->next)
12082       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12083       eb/jump loop/disp8
12084     }
12085 $populate-mu-type-sizes:offsets:
12086     # curr = *Program->types
12087     (lookup *_Program-types *_Program-types->payload)  # => eax
12088     {
12089       # if (curr == null) break
12090       3d/compare-eax-and 0/imm32/null
12091       74/jump-if-= break/disp8
12092       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
12093       # curr = curr->next
12094       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12095       eb/jump loop/disp8
12096     }
12097 $populate-mu-type-sizes:end:
12098     # . epilogue
12099     89/<- %esp 5/r32/ebp
12100     5d/pop-to-ebp
12101     c3/return
12102 
12103 # compute sizes of all fields, recursing as necessary
12104 # sum up all their sizes to arrive at total size
12105 # fields may be out of order, but that doesn't affect the answer
12106 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12107     # . prologue
12108     55/push-ebp
12109     89/<- %ebp 4/r32/esp
12110     # . save registers
12111     50/push-eax
12112     51/push-ecx
12113     52/push-edx
12114     56/push-esi
12115     57/push-edi
12116     # esi = T
12117     8b/-> *(ebp+8) 6/r32/esi
12118     # if T is already computed, return
12119     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
12120     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
12121     # if T is being computed, abort
12122     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12123     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
12124     # tag T (-2 to -1) to avoid infinite recursion
12125     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
12126     # var total-size/edi: int = 0
12127     bf/copy-to-edi 0/imm32
12128     # - for every field, if it's a user-defined type, compute its size
12129     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12130     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12131     89/<- %ecx 0/r32/eax
12132     # var table-size/edx: int = table->write
12133     8b/-> *ecx 2/r32/edx  # stream-write
12134     # var curr/ecx: (addr table_row) = table->data
12135     8d/copy-address *(ecx+0xc) 1/r32/ecx
12136     # var max/edx: (addr table_row) = table->data + table->write
12137     8d/copy-address *(ecx+edx) 2/r32/edx
12138     {
12139 $populate-mu-type-sizes-in-type:loop:
12140       # if (curr >= max) break
12141       39/compare %ecx 2/r32/edx
12142       73/jump-if-addr>= break/disp8
12143       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
12144       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12145       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
12146       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
12147       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
12148       # compute size of t->input-var
12149       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12150       (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
12151       # result += eax
12152       01/add-to %edi 0/r32/eax
12153       # curr += row-size
12154       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12155       #
12156       eb/jump loop/disp8
12157     }
12158     # - save result
12159     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
12160 $populate-mu-type-sizes-in-type:end:
12161     # . restore registers
12162     5f/pop-to-edi
12163     5e/pop-to-esi
12164     5a/pop-to-edx
12165     59/pop-to-ecx
12166     58/pop-to-eax
12167     # . epilogue
12168     89/<- %esp 5/r32/ebp
12169     5d/pop-to-ebp
12170     c3/return
12171 
12172 $populate-mu-type-sizes-in-type:abort:
12173     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
12174     (flush *(ebp+0xc))
12175     (stop *(ebp+0x10) 1)
12176     # never gets here
12177 
12178 # Analogous to size-of, except we need to compute what size-of can just read
12179 # off the right data structures.
12180 compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12181     # . prologue
12182     55/push-ebp
12183     89/<- %ebp 4/r32/esp
12184     # . push registers
12185     51/push-ecx
12186     # var t/ecx: (addr type-tree) = lookup(v->type)
12187     8b/-> *(ebp+8) 1/r32/ecx
12188     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12189     89/<- %ecx 0/r32/eax
12190     # if (t->is-atom == false) t = lookup(t->left)
12191     {
12192       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12193       75/jump-if-!= break/disp8
12194       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12195       89/<- %ecx 0/r32/eax
12196     }
12197     # TODO: ensure t is an atom
12198     (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
12199 $compute-size-of-var:end:
12200     # . restore registers
12201     59/pop-to-ecx
12202     # . epilogue
12203     89/<- %esp 5/r32/ebp
12204     5d/pop-to-ebp
12205     c3/return
12206 
12207 compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
12208     # . prologue
12209     55/push-ebp
12210     89/<- %ebp 4/r32/esp
12211     # . save registers
12212     51/push-ecx
12213     # var out/ecx: (handle typeinfo)
12214     68/push 0/imm32
12215     68/push 0/imm32
12216     89/<- %ecx 4/r32/esp
12217     # eax = t
12218     8b/-> *(ebp+8) 0/r32/eax
12219     # if t is a literal, return 0
12220     3d/compare-eax-and 0/imm32/literal
12221     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
12222     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12223     3d/compare-eax-and 8/imm32/byte
12224     {
12225       75/jump-if-!= break/disp8
12226       b8/copy-to-eax 4/imm32
12227       eb/jump $compute-size-of-type-id:end/disp8
12228     }
12229     # if t is a handle, return 8
12230     3d/compare-eax-and 4/imm32/handle
12231     {
12232       75/jump-if-!= break/disp8
12233       b8/copy-to-eax 8/imm32
12234       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12235     }
12236     # if t is a slice, return 8
12237     3d/compare-eax-and 0xc/imm32/slice
12238     {
12239       75/jump-if-!= break/disp8
12240       b8/copy-to-eax 8/imm32
12241       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
12242     }
12243     # if t is a user-defined type, compute its size
12244     # TODO: support non-atom type
12245     (find-typeinfo %eax %ecx)
12246     {
12247       81 7/subop/compare *ecx 0/imm32
12248       74/jump-if-= break/disp8
12249 $compute-size-of-type-id:user-defined:
12250       (lookup *ecx *(ecx+4))  # => eax
12251       (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
12252       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12253       eb/jump $compute-size-of-type-id:end/disp8
12254     }
12255     # otherwise return the word size
12256     b8/copy-to-eax 4/imm32
12257 $compute-size-of-type-id:end:
12258     # . reclaim locals
12259     81 0/subop/add %esp 8/imm32
12260     # . restore registers
12261     59/pop-to-ecx
12262     # . epilogue
12263     89/<- %esp 5/r32/ebp
12264     5d/pop-to-ebp
12265     c3/return
12266 
12267 # at this point we have total sizes for all user-defined types
12268 # compute offsets for each element
12269 # complication: fields may be out of order
12270 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
12271     # . prologue
12272     55/push-ebp
12273     89/<- %ebp 4/r32/esp
12274     # . save registers
12275     50/push-eax
12276     51/push-ecx
12277     52/push-edx
12278     53/push-ebx
12279     56/push-esi
12280     57/push-edi
12281 #?     (dump-typeinfos "aaa\n")
12282     # var curr-offset/edi: int = 0
12283     bf/copy-to-edi 0/imm32
12284     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
12285     8b/-> *(ebp+8) 1/r32/ecx
12286     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
12287     89/<- %ecx 0/r32/eax
12288     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
12289     8b/-> *ecx 2/r32/edx  # stream-write
12290     c1 5/subop/shift-right-logical  %edx 4/imm8
12291     # var i/ebx: int = 0
12292     bb/copy-to-ebx 0/imm32
12293     {
12294 $populate-mu-type-offsets:loop:
12295       39/compare %ebx 2/r32/edx
12296       0f 8d/jump-if->= break/disp32
12297 #?       (write-buffered Stderr "looking up index ")
12298 #?       (write-int32-hex-buffered Stderr %ebx)
12299 #?       (write-buffered Stderr " in ")
12300 #?       (write-int32-hex-buffered Stderr *(ebp+8))
12301 #?       (write-buffered Stderr Newline)
12302 #?       (flush Stderr)
12303       # var v/esi: (addr typeinfo-entry)
12304       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
12305       89/<- %esi 0/r32/eax
12306       # if v is null, silently move on; we'll emit a nice error message while type-checking
12307       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
12308       74/jump-if-= $populate-mu-type-offsets:end/disp8
12309       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
12310       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
12311       74/jump-if-= $populate-mu-type-offsets:end/disp8
12312       # v->output-var->offset = curr-offset
12313       # . eax: (addr var)
12314       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
12315       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
12316       # curr-offset += size-of(v->input-var)
12317       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
12318       (size-of %eax)  # => eax
12319       01/add-to %edi 0/r32/eax
12320       # ++i
12321       43/increment-ebx
12322       e9/jump loop/disp32
12323     }
12324 $populate-mu-type-offsets:end:
12325     # . restore registers
12326     5f/pop-to-edi
12327     5e/pop-to-esi
12328     5b/pop-to-ebx
12329     5a/pop-to-edx
12330     59/pop-to-ecx
12331     58/pop-to-eax
12332     # . epilogue
12333     89/<- %esp 5/r32/ebp
12334     5d/pop-to-ebp
12335     c3/return
12336 
12337 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)
12338     # . prologue
12339     55/push-ebp
12340     89/<- %ebp 4/r32/esp
12341     # . save registers
12342     51/push-ecx
12343     52/push-edx
12344     53/push-ebx
12345     56/push-esi
12346     57/push-edi
12347     # esi = table
12348     8b/-> *(ebp+8) 6/r32/esi
12349     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
12350     8d/copy-address *(esi+0xc) 1/r32/ecx
12351     # var max/edx: (addr byte) = &table->data[table->write]
12352     8b/-> *esi 2/r32/edx
12353     8d/copy-address *(ecx+edx) 2/r32/edx
12354     {
12355 $locate-typeinfo-entry-with-index:loop:
12356       39/compare %ecx 2/r32/edx
12357       73/jump-if-addr>= break/disp8
12358       # var v/eax: (addr typeinfo-entry)
12359       (lookup *(ecx+8) *(ecx+0xc))  # => eax
12360       # if (v->index == idx) return v
12361       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
12362 #?       (write-buffered Stderr "comparing ")
12363 #?       (write-int32-hex-buffered Stderr %ebx)
12364 #?       (write-buffered Stderr " and ")
12365 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
12366 #?       (write-buffered Stderr Newline)
12367 #?       (flush Stderr)
12368       39/compare *(ebp+0xc) 3/r32/ebx
12369       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
12370       # curr += Typeinfo-entry-size
12371       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
12372       #
12373       eb/jump loop/disp8
12374     }
12375     # return 0
12376     b8/copy-to-eax 0/imm32
12377 $locate-typeinfo-entry-with-index:end:
12378 #?     (write-buffered Stderr "returning ")
12379 #?     (write-int32-hex-buffered Stderr %eax)
12380 #?     (write-buffered Stderr Newline)
12381 #?     (flush Stderr)
12382     # . restore registers
12383     5f/pop-to-edi
12384     5e/pop-to-esi
12385     5b/pop-to-ebx
12386     5a/pop-to-edx
12387     59/pop-to-ecx
12388     # . epilogue
12389     89/<- %esp 5/r32/ebp
12390     5d/pop-to-ebp
12391     c3/return
12392 
12393 dump-typeinfos:  # hdr: (addr array byte)
12394     # . prologue
12395     55/push-ebp
12396     89/<- %ebp 4/r32/esp
12397     # . save registers
12398     50/push-eax
12399     #
12400     (write-buffered Stderr *(ebp+8))
12401     (flush Stderr)
12402     # var curr/eax: (addr typeinfo) = lookup(Program->types)
12403     (lookup *_Program-types *_Program-types->payload)  # => eax
12404     {
12405       # if (curr == null) break
12406       3d/compare-eax-and 0/imm32
12407       74/jump-if-= break/disp8
12408       (write-buffered Stderr "---\n")
12409       (flush Stderr)
12410       (dump-typeinfo %eax)
12411       # curr = lookup(curr->next)
12412       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
12413       eb/jump loop/disp8
12414     }
12415 $dump-typeinfos:end:
12416     # . restore registers
12417     58/pop-to-eax
12418     # . epilogue
12419     89/<- %esp 5/r32/ebp
12420     5d/pop-to-ebp
12421     c3/return
12422 
12423 dump-typeinfo:  # in: (addr typeinfo)
12424     # . prologue
12425     55/push-ebp
12426     89/<- %ebp 4/r32/esp
12427     # . save registers
12428     50/push-eax
12429     51/push-ecx
12430     52/push-edx
12431     53/push-ebx
12432     56/push-esi
12433     57/push-edi
12434     # esi = in
12435     8b/-> *(ebp+8) 6/r32/esi
12436     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
12437     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
12438     89/<- %ecx 0/r32/eax
12439     (write-buffered Stderr "id:")
12440     (write-int32-hex-buffered Stderr *esi)
12441     (write-buffered Stderr "\n")
12442     (write-buffered Stderr "fields @ ")
12443     (write-int32-hex-buffered Stderr %ecx)
12444     (write-buffered Stderr Newline)
12445     (flush Stderr)
12446     (write-buffered Stderr "  write: ")
12447     (write-int32-hex-buffered Stderr *ecx)
12448     (write-buffered Stderr Newline)
12449     (flush Stderr)
12450     (write-buffered Stderr "  read: ")
12451     (write-int32-hex-buffered Stderr *(ecx+4))
12452     (write-buffered Stderr Newline)
12453     (flush Stderr)
12454     (write-buffered Stderr "  size: ")
12455     (write-int32-hex-buffered Stderr *(ecx+8))
12456     (write-buffered Stderr Newline)
12457     (flush Stderr)
12458     # var table-size/edx: int = table->write
12459     8b/-> *ecx 2/r32/edx  # stream-write
12460     # var curr/ecx: (addr table_row) = table->data
12461     8d/copy-address *(ecx+0xc) 1/r32/ecx
12462     # var max/edx: (addr table_row) = table->data + table->write
12463     8d/copy-address *(ecx+edx) 2/r32/edx
12464     {
12465 $dump-typeinfo:loop:
12466       # if (curr >= max) break
12467       39/compare %ecx 2/r32/edx
12468       0f 83/jump-if-addr>= break/disp32
12469       (write-buffered Stderr "  row:\n")
12470       (write-buffered Stderr "    key: ")
12471       (write-int32-hex-buffered Stderr *ecx)
12472       (write-buffered Stderr ",")
12473       (write-int32-hex-buffered Stderr *(ecx+4))
12474       (write-buffered Stderr " = '")
12475       (lookup *ecx *(ecx+4))
12476       (write-buffered Stderr %eax)
12477       (write-buffered Stderr "' @ ")
12478       (write-int32-hex-buffered Stderr %eax)
12479       (write-buffered Stderr Newline)
12480       (flush Stderr)
12481       (write-buffered Stderr "    value: ")
12482       (write-int32-hex-buffered Stderr *(ecx+8))
12483       (write-buffered Stderr ",")
12484       (write-int32-hex-buffered Stderr *(ecx+0xc))
12485       (write-buffered Stderr " = typeinfo-entry@")
12486       (lookup *(ecx+8) *(ecx+0xc))
12487       (write-int32-hex-buffered Stderr %eax)
12488       (write-buffered Stderr Newline)
12489       (flush Stderr)
12490       (write-buffered Stderr "        input var@")
12491       (dump-var 5 %eax)
12492       (lookup *(ecx+8) *(ecx+0xc))
12493       (write-buffered Stderr "        index: ")
12494       (write-int32-hex-buffered Stderr *(eax+8))
12495       (write-buffered Stderr Newline)
12496       (flush Stderr)
12497       (write-buffered Stderr "        output var@")
12498       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
12499       (dump-var 5 %eax)
12500       (flush Stderr)
12501       # curr += row-size
12502       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
12503       #
12504       e9/jump loop/disp32
12505     }
12506 $dump-typeinfo:end:
12507     # . restore registers
12508     5f/pop-to-edi
12509     5e/pop-to-esi
12510     5b/pop-to-ebx
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 dump-var:  # indent: int, v: (addr handle var)
12520     # . prologue
12521     55/push-ebp
12522     89/<- %ebp 4/r32/esp
12523     # . save registers
12524     50/push-eax
12525     53/push-ebx
12526     # eax = v
12527     8b/-> *(ebp+0xc) 0/r32/eax
12528     #
12529     (write-int32-hex-buffered Stderr *eax)
12530     (write-buffered Stderr ",")
12531     (write-int32-hex-buffered Stderr *(eax+4))
12532     (write-buffered Stderr "->")
12533     (lookup *eax *(eax+4))
12534     (write-int32-hex-buffered Stderr %eax)
12535     (write-buffered Stderr Newline)
12536     (flush Stderr)
12537     {
12538       3d/compare-eax-and 0/imm32
12539       0f 84/jump-if-= break/disp32
12540       (emit-indent Stderr *(ebp+8))
12541       (write-buffered Stderr "name: ")
12542       89/<- %ebx 0/r32/eax
12543       (write-int32-hex-buffered Stderr *ebx)  # Var-name
12544       (write-buffered Stderr ",")
12545       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
12546       (write-buffered Stderr "->")
12547       (lookup *ebx *(ebx+4))  # Var-name
12548       (write-int32-hex-buffered Stderr %eax)
12549       {
12550         3d/compare-eax-and 0/imm32
12551         74/jump-if-= break/disp8
12552         (write-buffered Stderr Space)
12553         (write-buffered Stderr %eax)
12554       }
12555       (write-buffered Stderr Newline)
12556       (flush Stderr)
12557       (emit-indent Stderr *(ebp+8))
12558       (write-buffered Stderr "block depth: ")
12559       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
12560       (write-buffered Stderr Newline)
12561       (flush Stderr)
12562       (emit-indent Stderr *(ebp+8))
12563       (write-buffered Stderr "stack offset: ")
12564       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
12565       (write-buffered Stderr Newline)
12566       (flush Stderr)
12567       (emit-indent Stderr *(ebp+8))
12568       (write-buffered Stderr "reg: ")
12569       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
12570       (write-buffered Stderr ",")
12571       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
12572       (write-buffered Stderr "->")
12573       (flush Stderr)
12574       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
12575       (write-int32-hex-buffered Stderr %eax)
12576       {
12577         3d/compare-eax-and 0/imm32
12578         74/jump-if-= break/disp8
12579         (write-buffered Stderr Space)
12580         (write-buffered Stderr %eax)
12581       }
12582       (write-buffered Stderr Newline)
12583       (flush Stderr)
12584     }
12585 $dump-var:end:
12586     # . restore registers
12587     5b/pop-to-ebx
12588     58/pop-to-eax
12589     # . epilogue
12590     89/<- %esp 5/r32/ebp
12591     5d/pop-to-ebp
12592     c3/return
12593 
12594 #######################################################
12595 # Type-checking
12596 #######################################################
12597 
12598 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
12599     # . prologue
12600     55/push-ebp
12601     89/<- %ebp 4/r32/esp
12602     # . save registers
12603     50/push-eax
12604     # var curr/eax: (addr function) = lookup(Program->functions)
12605     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12606     {
12607 $check-mu-types:loop:
12608       # if (curr == null) break
12609       3d/compare-eax-and 0/imm32
12610       0f 84/jump-if-= break/disp32
12611 +--  8 lines: #?       # dump curr->name ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12619       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
12620       # curr = lookup(curr->next)
12621       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
12622       e9/jump loop/disp32
12623     }
12624 $check-mu-types:end:
12625     # . restore registers
12626     58/pop-to-eax
12627     # . epilogue
12628     89/<- %esp 5/r32/ebp
12629     5d/pop-to-ebp
12630     c3/return
12631 
12632 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12633     # . prologue
12634     55/push-ebp
12635     89/<- %ebp 4/r32/esp
12636     # . save registers
12637     50/push-eax
12638     # eax = f
12639     8b/-> *(ebp+8) 0/r32/eax
12640     # TODO: anything to check in header?
12641     # var body/eax: (addr block) = lookup(f->body)
12642     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
12643     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
12644 $check-mu-function:end:
12645     # . restore registers
12646     58/pop-to-eax
12647     # . epilogue
12648     89/<- %esp 5/r32/ebp
12649     5d/pop-to-ebp
12650     c3/return
12651 
12652 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12653     # . prologue
12654     55/push-ebp
12655     89/<- %ebp 4/r32/esp
12656     # . save registers
12657     50/push-eax
12658     # eax = block
12659     8b/-> *(ebp+8) 0/r32/eax
12660     # var stmts/eax: (addr list stmt) = lookup(block->statements)
12661     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
12662     #
12663     {
12664 $check-mu-block:check-empty:
12665       3d/compare-eax-and 0/imm32
12666       0f 84/jump-if-= break/disp32
12667       # emit block->statements
12668       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12669     }
12670 $check-mu-block:end:
12671     # . restore registers
12672     58/pop-to-eax
12673     # . epilogue
12674     89/<- %esp 5/r32/ebp
12675     5d/pop-to-ebp
12676     c3/return
12677 
12678 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12679     # . prologue
12680     55/push-ebp
12681     89/<- %ebp 4/r32/esp
12682     # . save registers
12683     50/push-eax
12684     56/push-esi
12685     # esi = stmts
12686     8b/-> *(ebp+8) 6/r32/esi
12687     {
12688 $check-mu-stmt-list:loop:
12689       81 7/subop/compare %esi 0/imm32
12690       0f 84/jump-if-= break/disp32
12691       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
12692       (lookup *esi *(esi+4))  # List-value List-value => eax
12693       {
12694 $check-mu-stmt-list:check-for-block:
12695         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
12696         75/jump-if-!= break/disp8
12697 $check-mu-stmt-list:block:
12698         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12699         eb/jump $check-mu-stmt-list:continue/disp8
12700       }
12701       {
12702 $check-mu-stmt-list:check-for-stmt1:
12703         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
12704         0f 85/jump-if-!= break/disp32
12705 $check-mu-stmt-list:stmt1:
12706         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12707         eb/jump $check-mu-stmt-list:continue/disp8
12708       }
12709       {
12710 $check-mu-stmt-list:check-for-reg-var-def:
12711         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
12712         0f 85/jump-if-!= break/disp32
12713 $check-mu-stmt-list:reg-var-def:
12714         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12715         eb/jump $check-mu-stmt-list:continue/disp8
12716       }
12717 $check-mu-stmt-list:continue:
12718       # TODO: raise an error on unrecognized Stmt-tag
12719       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
12720       89/<- %esi 0/r32/eax
12721       e9/jump loop/disp32
12722     }
12723 $check-mu-stmt-list:end:
12724     # . restore registers
12725     5e/pop-to-esi
12726     58/pop-to-eax
12727     # . epilogue
12728     89/<- %esp 5/r32/ebp
12729     5d/pop-to-ebp
12730     c3/return
12731 
12732 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12733     # . prologue
12734     55/push-ebp
12735     89/<- %ebp 4/r32/esp
12736     # . save registers
12737     50/push-eax
12738     # - if stmt's operation matches a primitive, check against it
12739     (has-primitive-name? *(ebp+8))  # => eax
12740     3d/compare-eax-and 0/imm32/false
12741     {
12742       74/jump-if-= break/disp8
12743       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12744       e9/jump $check-mu-stmt:end/disp32
12745     }
12746     # - otherwise find a function to check against
12747     # var f/eax: (addr function) = lookup(*Program->functions)
12748     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12749     (find-matching-function %eax *(ebp+8))  # => eax
12750     3d/compare-eax-and 0/imm32
12751     {
12752       74/jump-if-= break/disp8
12753       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12754       eb/jump $check-mu-stmt:end/disp8
12755     }
12756     # var f/eax: (addr function) = lookup(*Program->signatures)
12757     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
12758     (find-matching-function %eax *(ebp+8))  # => eax
12759     3d/compare-eax-and 0/imm32
12760     {
12761       74/jump-if-= break/disp8
12762       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12763       eb/jump $check-mu-stmt:end/disp8
12764     }
12765     # - otherwise abort
12766     e9/jump $check-mu-stmt:unknown-call/disp32
12767 $check-mu-stmt:end:
12768     # . restore registers
12769     58/pop-to-eax
12770     # . epilogue
12771     89/<- %esp 5/r32/ebp
12772     5d/pop-to-ebp
12773     c3/return
12774 
12775 $check-mu-stmt:unknown-call:
12776     (write-buffered *(ebp+0x10) "unknown function '")
12777     8b/-> *(ebp+8) 0/r32/eax
12778     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12779     (write-buffered *(ebp+0x10) %eax)
12780     (write-buffered *(ebp+0x10) "'\n")
12781     (flush *(ebp+0x10))
12782     (stop *(ebp+0x14) 1)
12783     # never gets here
12784 
12785 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
12786     # . prologue
12787     55/push-ebp
12788     89/<- %ebp 4/r32/esp
12789     # . save registers
12790     51/push-ecx
12791     56/push-esi
12792     # var name/esi: (addr array byte) = lookup(stmt->operation)
12793     8b/-> *(ebp+8) 6/r32/esi
12794     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
12795     89/<- %esi 0/r32/eax
12796     # if (name == "get") return true
12797     (string-equal? %esi "get")  # => eax
12798     3d/compare-eax-and 0/imm32/false
12799     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12800     # if (name == "index") return true
12801     (string-equal? %esi "index")  # => eax
12802     3d/compare-eax-and 0/imm32/false
12803     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12804     # if (name == "length") return true
12805     (string-equal? %esi "length")  # => eax
12806     3d/compare-eax-and 0/imm32/false
12807     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12808     # if (name == "compute-offset") return true
12809     (string-equal? %esi "compute-offset")  # => eax
12810     3d/compare-eax-and 0/imm32/false
12811     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12812     # if (name == "copy-object") return true
12813     (string-equal? %esi "copy-object")  # => eax
12814     3d/compare-eax-and 0/imm32/false
12815     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12816     # if (name == "allocate") return true
12817     (string-equal? %esi "allocate")  # => eax
12818     3d/compare-eax-and 0/imm32/false
12819     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12820     # if (name == "populate") return true
12821     (string-equal? %esi "populate")  # => eax
12822     3d/compare-eax-and 0/imm32/false
12823     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12824     # if (name == "populate-stream") return true
12825     (string-equal? %esi "populate-stream")  # => eax
12826     3d/compare-eax-and 0/imm32/false
12827     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12828     # if (name == "read-from-stream") return true
12829     (string-equal? %esi "read-from-stream")  # => eax
12830     3d/compare-eax-and 0/imm32/false
12831     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12832     # if (name == "write-to-stream") return true
12833     (string-equal? %esi "write-to-stream")  # => eax
12834     3d/compare-eax-and 0/imm32/false
12835     0f 85/jump-if-!= $has-primitive-name?:end/disp32
12836     # var curr/ecx: (addr primitive) = Primitives
12837     b9/copy-to-ecx Primitives/imm32
12838     {
12839 $has-primitive-name?:loop:
12840       # if (curr == null) break
12841       81 7/subop/compare %ecx 0/imm32
12842       74/jump-if-= break/disp8
12843       # if (primitive->name == name) return true
12844       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
12845       (string-equal? %esi %eax)  # => eax
12846       3d/compare-eax-and 0/imm32/false
12847       75/jump-if-!= $has-primitive-name?:end/disp8
12848 $has-primitive-name?:next-primitive:
12849       # curr = curr->next
12850       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
12851       89/<- %ecx 0/r32/eax
12852       #
12853       e9/jump loop/disp32
12854     }
12855     # return null
12856     b8/copy-to-eax 0/imm32
12857 $has-primitive-name?:end:
12858     # . restore registers
12859     5e/pop-to-esi
12860     59/pop-to-ecx
12861     # . epilogue
12862     89/<- %esp 5/r32/ebp
12863     5d/pop-to-ebp
12864     c3/return
12865 
12866 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12867     # . prologue
12868     55/push-ebp
12869     89/<- %ebp 4/r32/esp
12870     # . save registers
12871     50/push-eax
12872     51/push-ecx
12873     # var op/ecx: (addr array byte) = lookup(stmt->operation)
12874     8b/-> *(ebp+8) 0/r32/eax
12875     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12876     89/<- %ecx 0/r32/eax
12877     # if (op == "copy") check-mu-copy-stmt
12878     {
12879       (string-equal? %ecx "copy")  # => eax
12880       3d/compare-eax-and 0/imm32/false
12881       74/jump-if-= break/disp8
12882       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12883       e9/jump $check-mu-primitive:end/disp32
12884     }
12885     # if (op == "copy-to") check-mu-copy-to-stmt
12886     {
12887       (string-equal? %ecx "copy-to")  # => eax
12888       3d/compare-eax-and 0/imm32/false
12889       74/jump-if-= break/disp8
12890       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12891       e9/jump $check-mu-primitive:end/disp32
12892     }
12893     # if (op == "compare") check-mu-compare-stmt
12894     {
12895       (string-equal? %ecx "compare")  # => eax
12896       3d/compare-eax-and 0/imm32/false
12897       74/jump-if-= break/disp8
12898       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12899       e9/jump $check-mu-primitive:end/disp32
12900     }
12901     # if (op == "address") check-mu-address-stmt
12902     {
12903       (string-equal? %ecx "address")  # => eax
12904       3d/compare-eax-and 0/imm32/false
12905       74/jump-if-= break/disp8
12906       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12907       e9/jump $check-mu-primitive:end/disp32
12908     }
12909     # if (op == "get") check-mu-get-stmt
12910     {
12911       (string-equal? %ecx "get")  # => eax
12912       3d/compare-eax-and 0/imm32/false
12913       74/jump-if-= break/disp8
12914       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12915       e9/jump $check-mu-primitive:end/disp32
12916     }
12917     # if (op == "index") check-mu-index-stmt
12918     {
12919       (string-equal? %ecx "index")  # => eax
12920       3d/compare-eax-and 0/imm32/false
12921       74/jump-if-= break/disp8
12922       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12923       e9/jump $check-mu-primitive:end/disp32
12924     }
12925     # if (op == "length") check-mu-length-stmt
12926     {
12927       (string-equal? %ecx "length")  # => eax
12928       3d/compare-eax-and 0/imm32/false
12929       74/jump-if-= break/disp8
12930       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12931       e9/jump $check-mu-primitive:end/disp32
12932     }
12933     # if (op == "compute-offset") check-mu-compute-offset-stmt
12934     {
12935       (string-equal? %ecx "compute-offset")  # => eax
12936       3d/compare-eax-and 0/imm32/false
12937       74/jump-if-= break/disp8
12938       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12939       e9/jump $check-mu-primitive:end/disp32
12940     }
12941     # if (op == "copy-object") check-mu-copy-object-stmt
12942     {
12943       (string-equal? %ecx "copy-object")  # => eax
12944       3d/compare-eax-and 0/imm32/false
12945       74/jump-if-= break/disp8
12946       (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12947       e9/jump $check-mu-primitive:end/disp32
12948     }
12949     # if (op == "allocate") check-mu-allocate-stmt
12950     {
12951       (string-equal? %ecx "allocate")  # => eax
12952       3d/compare-eax-and 0/imm32/false
12953       74/jump-if-= break/disp8
12954       (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12955       e9/jump $check-mu-primitive:end/disp32
12956     }
12957     # if (op == "populate") check-mu-populate-stmt
12958     {
12959       (string-equal? %ecx "populate")  # => eax
12960       3d/compare-eax-and 0/imm32/false
12961       74/jump-if-= break/disp8
12962       (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12963       e9/jump $check-mu-primitive:end/disp32
12964     }
12965     # if (op == "populate-stream") check-mu-populate-stream-stmt
12966     {
12967       (string-equal? %ecx "populate-stream")  # => eax
12968       3d/compare-eax-and 0/imm32/false
12969       74/jump-if-= break/disp8
12970       (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12971       e9/jump $check-mu-primitive:end/disp32
12972     }
12973     # if (op == "read-from-stream") check-mu-read-from-stream-stmt
12974     {
12975       (string-equal? %ecx "read-from-stream")  # => eax
12976       3d/compare-eax-and 0/imm32/false
12977       74/jump-if-= break/disp8
12978       (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12979       e9/jump $check-mu-primitive:end/disp32
12980     }
12981     # if (op == "write-to-stream") check-mu-write-to-stream-stmt
12982     {
12983       (string-equal? %ecx "write-to-stream")  # => eax
12984       3d/compare-eax-and 0/imm32/false
12985       74/jump-if-= break/disp8
12986       (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12987       e9/jump $check-mu-primitive:end/disp32
12988     }
12989     # otherwise check-numberlike-stmt
12990     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12991 $check-mu-primitive:end:
12992     # . restore registers
12993     59/pop-to-ecx
12994     58/pop-to-eax
12995     # . epilogue
12996     89/<- %esp 5/r32/ebp
12997     5d/pop-to-ebp
12998     c3/return
12999 
13000 # by default, Mu primitives should only operate on 'number-like' types
13001 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13002     # . prologue
13003     55/push-ebp
13004     89/<- %ebp 4/r32/esp
13005     # . save registers
13006     50/push-eax
13007     51/push-ecx
13008     56/push-esi
13009     # esi = stmt
13010     8b/-> *(ebp+8) 6/r32/esi
13011     # var gas/ecx: int = 2
13012     b9/copy-to-ecx 2/imm32
13013     # - check at most 1 output
13014     # var output/eax: (addr stmt-var) = stmt->outputs
13015     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13016     {
13017       3d/compare-eax-and 0/imm32
13018       74/jump-if-= break/disp8
13019 $check-mu-numberlike-primitive:output:
13020       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13021       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13022       3d/compare-eax-and 0/imm32
13023       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
13024       # check output is in a register
13025       # --gas
13026       49/decrement-ecx
13027     }
13028     # - check first inout
13029     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13030     {
13031       3d/compare-eax-and 0/imm32
13032       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
13033 $check-mu-numberlike-primitive:first-inout:
13034       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13035       # --gas
13036       49/decrement-ecx
13037     }
13038     # - check second inout
13039     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13040     {
13041       3d/compare-eax-and 0/imm32
13042       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
13043 $check-mu-numberlike-primitive:second-inout:
13044       # is a second inout allowed?
13045       81 7/subop/compare %ecx 0/imm32
13046       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
13047 $check-mu-numberlike-primitive:second-inout-permitted:
13048       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13049     }
13050 $check-mu-numberlike-primitive:third-inout:
13051     # if there's a third arg, raise an error
13052     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
13053     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
13054 $check-mu-numberlike-primitive:end:
13055     # . restore registers
13056     5e/pop-to-esi
13057     59/pop-to-ecx
13058     58/pop-to-eax
13059     # . epilogue
13060     89/<- %esp 5/r32/ebp
13061     5d/pop-to-ebp
13062     c3/return
13063 
13064 $check-mu-numberlike-primitive:error-too-many-inouts:
13065     (write-buffered *(ebp+0x10) "fn ")
13066     8b/-> *(ebp+0xc) 0/r32/eax
13067     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13068     (write-buffered *(ebp+0x10) %eax)
13069     (write-buffered *(ebp+0x10) ": stmt ")
13070     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
13071     (write-buffered *(ebp+0x10) %eax)
13072     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
13073     (flush *(ebp+0x10))
13074     (stop *(ebp+0x14) 1)
13075     # never gets here
13076 
13077 $check-mu-numberlike-primitive:error-too-many-outputs:
13078     (write-buffered *(ebp+0x10) "fn ")
13079     8b/-> *(ebp+0xc) 0/r32/eax
13080     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13081     (write-buffered *(ebp+0x10) %eax)
13082     (write-buffered *(ebp+0x10) ": stmt ")
13083     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
13084     (write-buffered *(ebp+0x10) %eax)
13085     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
13086     (flush *(ebp+0x10))
13087     (stop *(ebp+0x14) 1)
13088     # never gets here
13089 
13090 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13091     # . prologue
13092     55/push-ebp
13093     89/<- %ebp 4/r32/esp
13094     # . save registers
13095     50/push-eax
13096     56/push-esi
13097     # var t/esi: (addr type-tree) = lookup(v->value->type)
13098     8b/-> *(ebp+8) 0/r32/eax
13099     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13100     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13101     89/<- %esi 0/r32/eax
13102 $check-mu-numberlike-arg:check-literal:
13103     # if t is an int, return
13104     (is-simple-mu-type? %esi 0)  # literal => eax
13105     3d/compare-eax-and 0/imm32/false
13106     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
13107 $check-mu-numberlike-arg:check-addr:
13108     # if t is an addr and v is dereferenced, return
13109     {
13110       (is-mu-addr-type? %esi)  # => eax
13111       3d/compare-eax-and 0/imm32/false
13112       74/jump-if-= break/disp8
13113       8b/-> *(ebp+8) 0/r32/eax
13114       8b/-> *(eax+0x10) 0/r32/eax
13115       3d/compare-eax-and 0/imm32/false
13116       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
13117     }
13118 $check-mu-numberlike-arg:output-checks:
13119     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
13120 $check-mu-numberlike-arg:end:
13121     # . restore registers
13122     5e/pop-to-esi
13123     58/pop-to-eax
13124     # . epilogue
13125     89/<- %esp 5/r32/ebp
13126     5d/pop-to-ebp
13127     c3/return
13128 
13129 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13130     # . prologue
13131     55/push-ebp
13132     89/<- %ebp 4/r32/esp
13133     # . save registers
13134     50/push-eax
13135     56/push-esi
13136     # var t/esi: (addr type-tree) = lookup(v->value->type)
13137     8b/-> *(ebp+8) 0/r32/eax
13138     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13139     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13140     89/<- %esi 0/r32/eax
13141 $check-mu-numberlike-output:check-int:
13142     # if t is an int, return
13143     (is-simple-mu-type? %esi 1)  # int => eax
13144     3d/compare-eax-and 0/imm32/false
13145     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13146 $check-mu-numberlike-output:check-boolean:
13147     # if t is a boolean, return
13148     (is-simple-mu-type? %esi 5)  # boolean => eax
13149     3d/compare-eax-and 0/imm32/false
13150     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13151 $check-mu-numberlike-output:check-byte:
13152     # if t is a byte, return
13153     (is-simple-mu-type? %esi 8)  # byte => eax
13154     3d/compare-eax-and 0/imm32/false
13155     75/jump-if-!= $check-mu-numberlike-output:end/disp8
13156     e9/jump $check-mu-numberlike-output:fail/disp32
13157 $check-mu-numberlike-output:end:
13158     # . restore registers
13159     5e/pop-to-esi
13160     58/pop-to-eax
13161     # . epilogue
13162     89/<- %esp 5/r32/ebp
13163     5d/pop-to-ebp
13164     c3/return
13165 
13166 $check-mu-numberlike-output:fail:
13167     # otherwise raise an error
13168     (write-buffered *(ebp+0x14) "fn ")
13169     8b/-> *(ebp+0x10) 0/r32/eax
13170     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13171     (write-buffered *(ebp+0x14) %eax)
13172     (write-buffered *(ebp+0x14) ": stmt ")
13173     8b/-> *(ebp+0xc) 0/r32/eax
13174     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13175     (write-buffered *(ebp+0x14) %eax)
13176     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
13177     (flush *(ebp+0x14))
13178     (stop *(ebp+0x18) 1)
13179     # never gets here
13180 
13181 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13182     # . prologue
13183     55/push-ebp
13184     89/<- %ebp 4/r32/esp
13185     # . save registers
13186 $check-mu-copy-stmt:end:
13187     # . restore registers
13188     # . epilogue
13189     89/<- %esp 5/r32/ebp
13190     5d/pop-to-ebp
13191     c3/return
13192 
13193 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13194     # . prologue
13195     55/push-ebp
13196     89/<- %ebp 4/r32/esp
13197     # . save registers
13198 $check-mu-copy-to-stmt:end:
13199     # . restore registers
13200     # . epilogue
13201     89/<- %esp 5/r32/ebp
13202     5d/pop-to-ebp
13203     c3/return
13204 
13205 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13206     # . prologue
13207     55/push-ebp
13208     89/<- %ebp 4/r32/esp
13209     # . save registers
13210 $check-mu-compare-stmt:end:
13211     # . restore registers
13212     # . epilogue
13213     89/<- %esp 5/r32/ebp
13214     5d/pop-to-ebp
13215     c3/return
13216 
13217 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13218     # . prologue
13219     55/push-ebp
13220     89/<- %ebp 4/r32/esp
13221     # . save registers
13222 $check-mu-address-stmt:end:
13223     # . restore registers
13224     # . epilogue
13225     89/<- %esp 5/r32/ebp
13226     5d/pop-to-ebp
13227     c3/return
13228 
13229 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13230     # . prologue
13231     55/push-ebp
13232     89/<- %ebp 4/r32/esp
13233     # . save registers
13234     50/push-eax
13235     51/push-ecx
13236     52/push-edx
13237     53/push-ebx
13238     56/push-esi
13239     57/push-edi
13240     # esi = stmt
13241     8b/-> *(ebp+8) 6/r32/esi
13242     # - check for 0 inouts
13243     # var base/ecx: (addr var) = stmt->inouts->value
13244     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13245     3d/compare-eax-and 0/imm32/false
13246     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13247     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13248     89/<- %ecx 0/r32/eax
13249 $check-mu-get-stmt:check-base:
13250     # - check base type
13251     # if it's an 'addr', check that it's in a register
13252     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13253     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13254     89/<- %ebx 0/r32/eax
13255     {
13256       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13257       0f 85/jump-if-!= break/disp32
13258 $check-mu-get-stmt:base-is-compound:
13259       # if (type->left != addr) break
13260       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13261       (is-simple-mu-type? %eax 2)  # addr => eax
13262       3d/compare-eax-and 0/imm32/false
13263       74/jump-if-= break/disp8
13264 $check-mu-get-stmt:base-is-addr:
13265       # now check for register
13266       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13267       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
13268 $check-mu-get-stmt:base-is-addr-in-register:
13269       # type->left is now an addr; skip it
13270       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13271       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
13272       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
13273 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
13274       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13275       89/<- %ebx 0/r32/eax
13276     }
13277 $check-mu-get-stmt:check-base-typeinfo:
13278     # ensure type is a container
13279     # var base-type-id/ebx: type-id = base-type->value
13280     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
13281     (is-container? %ebx)  # => eax
13282     3d/compare-eax-and 0/imm32/false
13283     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
13284     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
13285     # . var container/ecx: (handle typeinfo)
13286     68/push 0/imm32
13287     68/push 0/imm32
13288     89/<- %ecx 4/r32/esp
13289     # .
13290     (find-typeinfo %ebx %ecx)
13291     (lookup *ecx *(ecx+4))  # => eax
13292     # . reclaim container
13293     81 0/subop/add %esp 8/imm32
13294     # .
13295     89/<- %edx 0/r32/eax
13296     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
13297     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13298     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13299     89/<- %ecx 0/r32/eax
13300     # - check for 1 inout
13301     3d/compare-eax-and 0/imm32/false
13302     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
13303     # var offset/ecx: (addr var) = lookup(offset->value)
13304     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13305     89/<- %ecx 0/r32/eax
13306     # - check for valid field
13307     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
13308     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
13309     # - check for too many inouts
13310     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13311     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13312     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13313     3d/compare-eax-and 0/imm32/false
13314     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
13315     # var output/edi: (addr var) = stmt->outputs->value
13316     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13317     # - check for 0 outputs
13318     3d/compare-eax-and 0/imm32/false
13319     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
13320     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13321     89/<- %edi 0/r32/eax
13322 $check-mu-get-stmt:check-output-type:
13323     # - check output type
13324     # must be in register
13325     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13326     3d/compare-eax-and 0/imm32
13327     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
13328     # must have a non-atomic type
13329     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13330     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13331     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
13332     # type must start with (addr ...)
13333     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13334     (is-simple-mu-type? %eax 2)  # => eax
13335     3d/compare-eax-and 0/imm32/false
13336     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
13337 $check-mu-get-stmt:check-output-type-match:
13338     # payload of addr type must match 'type' definition
13339     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13340     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
13341     # if (payload->right == null) payload = payload->left
13342     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
13343     {
13344       75/jump-if-!= break/disp8
13345       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13346     }
13347     89/<- %edi 0/r32/eax
13348     # . var output-name/ecx: (addr array byte)
13349     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13350     89/<- %ecx 0/r32/eax
13351     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
13352     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
13353     (get %eax %ecx 0x10)  # => eax
13354     # .
13355     (lookup *eax *(eax+4))  # => eax
13356     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
13357     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
13358     # .
13359     (type-equal? %edi %eax)  # => eax
13360     3d/compare-eax-and 0/imm32/false
13361     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
13362     # - check for too many outputs
13363     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13364     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13365     3d/compare-eax-and 0/imm32/false
13366     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
13367 $check-mu-get-stmt:end:
13368     # . restore registers
13369     5f/pop-to-edi
13370     5e/pop-to-esi
13371     5b/pop-to-ebx
13372     5a/pop-to-edx
13373     59/pop-to-ecx
13374     58/pop-to-eax
13375     # . epilogue
13376     89/<- %esp 5/r32/ebp
13377     5d/pop-to-ebp
13378     c3/return
13379 
13380 $check-mu-get-stmt:error-too-few-inouts:
13381     (write-buffered *(ebp+0x10) "fn ")
13382     8b/-> *(ebp+0xc) 0/r32/eax
13383     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13384     (write-buffered *(ebp+0x10) %eax)
13385     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
13386     (flush *(ebp+0x10))
13387     (stop *(ebp+0x14) 1)
13388     # never gets here
13389 
13390 $check-mu-get-stmt:error-too-many-inouts:
13391     (write-buffered *(ebp+0x10) "fn ")
13392     8b/-> *(ebp+0xc) 0/r32/eax
13393     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13394     (write-buffered *(ebp+0x10) %eax)
13395     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
13396     (flush *(ebp+0x10))
13397     (stop *(ebp+0x14) 1)
13398     # never gets here
13399 
13400 $check-mu-get-stmt:error-too-few-outputs:
13401     (write-buffered *(ebp+0x10) "fn ")
13402     8b/-> *(ebp+0xc) 0/r32/eax
13403     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13404     (write-buffered *(ebp+0x10) %eax)
13405     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
13406     (flush *(ebp+0x10))
13407     (stop *(ebp+0x14) 1)
13408     # never gets here
13409 
13410 $check-mu-get-stmt:error-too-many-outputs:
13411     (write-buffered *(ebp+0x10) "fn ")
13412     8b/-> *(ebp+0xc) 0/r32/eax
13413     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13414     (write-buffered *(ebp+0x10) %eax)
13415     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
13416     (flush *(ebp+0x10))
13417     (stop *(ebp+0x14) 1)
13418     # never gets here
13419 
13420 $check-mu-get-stmt:error-bad-base:
13421     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
13422     (write-buffered *(ebp+0x10) "fn ")
13423     8b/-> *(ebp+0xc) 0/r32/eax
13424     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13425     (write-buffered *(ebp+0x10) %eax)
13426     (write-buffered *(ebp+0x10) ": stmt get: var '")
13427     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13428     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13429     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13430     (write-buffered *(ebp+0x10) %eax)
13431     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
13432     (flush *(ebp+0x10))
13433     (stop *(ebp+0x14) 1)
13434     # never gets here
13435 
13436 $check-mu-get-stmt:error-base-type-addr-but-not-register:
13437     (write-buffered *(ebp+0x10) "fn ")
13438     8b/-> *(ebp+0xc) 0/r32/eax
13439     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13440     (write-buffered *(ebp+0x10) %eax)
13441     (write-buffered *(ebp+0x10) ": stmt get: var '")
13442     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13443     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13444     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13445     (write-buffered *(ebp+0x10) %eax)
13446     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
13447     (flush *(ebp+0x10))
13448     (stop *(ebp+0x14) 1)
13449     # never gets here
13450 
13451 $check-mu-get-stmt:error-bad-field:
13452     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
13453     (write-buffered *(ebp+0x10) "fn ")
13454     8b/-> *(ebp+0xc) 0/r32/eax
13455     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13456     (write-buffered *(ebp+0x10) %eax)
13457     (write-buffered *(ebp+0x10) ": stmt get: type '")
13458     # . write(Type-id->data[tmp])
13459     bf/copy-to-edi Type-id/imm32
13460     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13461     # .
13462     (write-buffered *(ebp+0x10) "' has no member called '")
13463     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13464     (write-buffered *(ebp+0x10) %eax)
13465     (write-buffered *(ebp+0x10) "'\n")
13466     (flush *(ebp+0x10))
13467     (stop *(ebp+0x14) 1)
13468     # never gets here
13469 
13470 $check-mu-get-stmt:error-output-not-in-register:
13471     (write-buffered *(ebp+0x10) "fn ")
13472     8b/-> *(ebp+0xc) 0/r32/eax
13473     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13474     (write-buffered *(ebp+0x10) %eax)
13475     (write-buffered *(ebp+0x10) ": stmt get: output '")
13476     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13477     (write-buffered *(ebp+0x10) %eax)
13478     (write-buffered *(ebp+0x10) "' is not in a register\n")
13479     (flush *(ebp+0x10))
13480     (stop *(ebp+0x14) 1)
13481     # never gets here
13482 
13483 $check-mu-get-stmt:error-output-type-not-address:
13484     (write-buffered *(ebp+0x10) "fn ")
13485     8b/-> *(ebp+0xc) 0/r32/eax
13486     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13487     (write-buffered *(ebp+0x10) %eax)
13488     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
13489     (flush *(ebp+0x10))
13490     (stop *(ebp+0x14) 1)
13491     # never gets here
13492 
13493 $check-mu-get-stmt:error-bad-output-type:
13494     (write-buffered *(ebp+0x10) "fn ")
13495     8b/-> *(ebp+0xc) 0/r32/eax
13496     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13497     (write-buffered *(ebp+0x10) %eax)
13498     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
13499     (write-buffered *(ebp+0x10) %ecx)
13500     (write-buffered *(ebp+0x10) "' of type '")
13501     bf/copy-to-edi Type-id/imm32
13502     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
13503     (write-buffered *(ebp+0x10) "'\n")
13504     (flush *(ebp+0x10))
13505     (stop *(ebp+0x14) 1)
13506     # never gets here
13507 
13508 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13509     # . prologue
13510     55/push-ebp
13511     89/<- %ebp 4/r32/esp
13512     # . save registers
13513     50/push-eax
13514     51/push-ecx
13515     52/push-edx
13516     53/push-ebx
13517     56/push-esi
13518     57/push-edi
13519     # esi = stmt
13520     8b/-> *(ebp+8) 6/r32/esi
13521     # - check for 0 inouts
13522     # var base/ecx: (addr var) = stmt->inouts->value
13523     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13524 $check-mu-index-stmt:check-no-inouts:
13525     3d/compare-eax-and 0/imm32
13526     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13527     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13528     89/<- %ecx 0/r32/eax
13529     # - check base type is either (addr array ...) in register or (array ...) on stack
13530     # var base-type/ebx: (addr type-tree) = lookup(base->type)
13531     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13532     89/<- %ebx 0/r32/eax
13533     # if base-type is an atom, abort with a precise error
13534     81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
13535     {
13536       74/jump-if-= break/disp8
13537       (is-simple-mu-type? %ebx 3)  # array => eax
13538       3d/compare-eax-and 0/imm32/false
13539       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
13540       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13541     }
13542 $check-mu-index-stmt:base-is-compound:
13543     # if type->left not addr or array, abort
13544     {
13545       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13546       (is-simple-mu-type? %eax 2)  # addr => eax
13547       3d/compare-eax-and 0/imm32/false
13548       75/jump-if-!= break/disp8
13549       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13550       (is-simple-mu-type? %eax 3)  # array => eax
13551       3d/compare-eax-and 0/imm32/false
13552       75/jump-if-!= break/disp8
13553       e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
13554     }
13555     # if (type->left == addr) ensure type->right->left == array and type->register exists
13556     {
13557       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13558       (is-simple-mu-type? %eax 2)  # addr => eax
13559       3d/compare-eax-and 0/imm32/false
13560       74/jump-if-= break/disp8
13561 $check-mu-index-stmt:base-is-addr:
13562       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13563       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13564       (is-simple-mu-type? %eax 3)  # array => eax
13565       3d/compare-eax-and 0/imm32/false
13566       0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
13567 $check-mu-index-stmt:check-base-addr-is-register:
13568       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13569       0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
13570     }
13571     # if (type->left == array) ensure type->register doesn't exist
13572     {
13573       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13574       (is-simple-mu-type? %eax 3)  # array => eax
13575       3d/compare-eax-and 0/imm32/false
13576       74/jump-if-= break/disp8
13577 $check-mu-index-stmt:base-is-array:
13578       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13579       0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
13580     }
13581     # if (base-type->left == addr) base-type = base-type->right
13582     {
13583       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
13584       (is-simple-mu-type? %eax 2)  # addr => eax
13585       3d/compare-eax-and 0/imm32/false
13586       74/jump-if-= break/disp8
13587       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
13588       89/<- %ebx 0/r32/eax
13589     }
13590     # - check for 1 inout
13591     # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
13592     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13593     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13594 $check-mu-index-stmt:check-single-inout:
13595     3d/compare-eax-and 0/imm32
13596     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
13597     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13598     89/<- %ecx 0/r32/eax
13599     # - check index is either a literal or register
13600     # var index-type/edx: (addr type-tree)
13601     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13602     89/<- %edx 0/r32/eax
13603     # if index type is an atom, it must be a literal or int
13604     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13605     {
13606       74/jump-if-= break/disp8
13607 $check-mu-index-stmt:index-type-is-atom:
13608       (is-simple-mu-type? %edx 0)  # literal => eax
13609       3d/compare-eax-and 0/imm32/false
13610       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13611       (is-simple-mu-type? %edx 1)  # int => eax
13612       3d/compare-eax-and 0/imm32/false
13613       75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
13614       (is-simple-mu-type? %edx 7)  # offset => eax
13615       3d/compare-eax-and 0/imm32/false
13616       0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
13617       e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
13618     }
13619     # if index type is a non-atom: it must be an offset
13620     {
13621       75/jump-if-!= break/disp8
13622 $check-mu-index-stmt:index-type-is-non-atom:
13623       (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13624       (is-simple-mu-type? %eax 7)  # offset => eax
13625       3d/compare-eax-and 0/imm32/false
13626       0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
13627     }
13628 $check-mu-index-stmt:index-type-done:
13629     # check index is either a literal or in a register
13630     {
13631       (is-simple-mu-type? %edx 0)  # literal => eax
13632       3d/compare-eax-and 0/imm32/false
13633       75/jump-if-!= break/disp8
13634 $check-mu-index-stmt:check-index-in-register:
13635       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13636       0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
13637     }
13638     # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
13639     {
13640       (is-simple-mu-type? %edx 1)  # int => eax
13641       3d/compare-eax-and 0/imm32/false
13642       74/jump-if-= break/disp8
13643 $check-mu-index-stmt:check-index-can-be-int:
13644       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13645       (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13646       (array-element-size %eax)  # => eax
13647       3d/compare-eax-and 1/imm32
13648       74/jump-if-= break/disp8
13649       3d/compare-eax-and 2/imm32
13650       74/jump-if-= break/disp8
13651       3d/compare-eax-and 4/imm32
13652       74/jump-if-= break/disp8
13653       3d/compare-eax-and 8/imm32
13654       74/jump-if-= break/disp8
13655       e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
13656     }
13657     # - check for too many inouts
13658     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13659     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13660     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13661     3d/compare-eax-and 0/imm32/false
13662     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32
13663     # - check for 0 outputs
13664     # var output/edi: (addr var) = stmt->outputs->value
13665     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13666     3d/compare-eax-and 0/imm32/false
13667     0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
13668     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13669     89/<- %edi 0/r32/eax
13670     # - check output type
13671     # must have a non-atomic type
13672     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13673     89/<- %edx 0/r32/eax
13674     81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
13675     0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
13676     # type must start with (addr ...)
13677     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
13678     (is-simple-mu-type? %eax 2)  # addr => eax
13679     3d/compare-eax-and 0/imm32/false
13680     0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
13681     # if tail(base-type) != tail(output-type) abort
13682     (type-tail %ebx)  # => eax
13683     89/<- %ebx 0/r32/eax
13684     (type-tail %edx)  # => eax
13685     (type-equal? %ebx %eax)  # => eax
13686     3d/compare-eax-and 0/imm32/false
13687     0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
13688     # - check for too many outputs
13689     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13690     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13691     3d/compare-eax-and 0/imm32/false
13692     0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
13693 $check-mu-index-stmt:end:
13694     # . restore registers
13695     5f/pop-to-edi
13696     5e/pop-to-esi
13697     5b/pop-to-ebx
13698     5a/pop-to-edx
13699     59/pop-to-ecx
13700     58/pop-to-eax
13701     # . epilogue
13702     89/<- %esp 5/r32/ebp
13703     5d/pop-to-ebp
13704     c3/return
13705 
13706 $check-mu-index-stmt:error-base-non-array-type:
13707     (write-buffered *(ebp+0x10) "fn ")
13708     8b/-> *(ebp+0xc) 0/r32/eax
13709     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13710     (write-buffered *(ebp+0x10) %eax)
13711     (write-buffered *(ebp+0x10) ": stmt index: var '")
13712     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13713     (write-buffered *(ebp+0x10) %eax)
13714     (write-buffered *(ebp+0x10) "' is not an array\n")
13715     (flush *(ebp+0x10))
13716     (stop *(ebp+0x14) 1)
13717     # never gets here
13718 
13719 $check-mu-index-stmt:error-base-array-atom-type:
13720     (write-buffered *(ebp+0x10) "fn ")
13721     8b/-> *(ebp+0xc) 0/r32/eax
13722     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13723     (write-buffered *(ebp+0x10) %eax)
13724     (write-buffered *(ebp+0x10) ": stmt index: array '")
13725     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13726     (write-buffered *(ebp+0x10) %eax)
13727     (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
13728     (flush *(ebp+0x10))
13729     (stop *(ebp+0x14) 1)
13730     # never gets here
13731 
13732 $check-mu-index-stmt:error-base-address-array-type-on-stack:
13733     (write-buffered *(ebp+0x10) "fn ")
13734     8b/-> *(ebp+0xc) 0/r32/eax
13735     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13736     (write-buffered *(ebp+0x10) %eax)
13737     (write-buffered *(ebp+0x10) ": stmt index: var '")
13738     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13739     (write-buffered *(ebp+0x10) %eax)
13740     (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
13741     (flush *(ebp+0x10))
13742     (stop *(ebp+0x14) 1)
13743     # never gets here
13744 
13745 $check-mu-index-stmt:error-base-array-type-in-register:
13746     (write-buffered *(ebp+0x10) "fn ")
13747     8b/-> *(ebp+0xc) 0/r32/eax
13748     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13749     (write-buffered *(ebp+0x10) %eax)
13750     (write-buffered *(ebp+0x10) ": stmt index: var '")
13751     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13752     (write-buffered *(ebp+0x10) %eax)
13753     (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
13754     (flush *(ebp+0x10))
13755     (stop *(ebp+0x14) 1)
13756     # never gets here
13757 
13758 $check-mu-index-stmt:error-too-few-inouts:
13759     (write-buffered *(ebp+0x10) "fn ")
13760     8b/-> *(ebp+0xc) 0/r32/eax
13761     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13762     (write-buffered *(ebp+0x10) %eax)
13763     (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
13764     (flush *(ebp+0x10))
13765     (stop *(ebp+0x14) 1)
13766     # never gets here
13767 
13768 $check-mu-index-stmt:error-invalid-index-type:
13769     (write-buffered *(ebp+0x10) "fn ")
13770     8b/-> *(ebp+0xc) 0/r32/eax
13771     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13772     (write-buffered *(ebp+0x10) %eax)
13773     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13774     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13775     (write-buffered *(ebp+0x10) %eax)
13776     (write-buffered *(ebp+0x10) "' must be an int or offset\n")
13777     (flush *(ebp+0x10))
13778     (stop *(ebp+0x14) 1)
13779     # never gets here
13780 
13781 $check-mu-index-stmt:error-index-offset-atom-type:
13782     (write-buffered *(ebp+0x10) "fn ")
13783     8b/-> *(ebp+0xc) 0/r32/eax
13784     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13785     (write-buffered *(ebp+0x10) %eax)
13786     (write-buffered *(ebp+0x10) ": stmt index: offset '")
13787     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13788     (write-buffered *(ebp+0x10) %eax)
13789     (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
13790     (flush *(ebp+0x10))
13791     (stop *(ebp+0x14) 1)
13792     # never gets here
13793 
13794 $check-mu-index-stmt:error-index-on-stack:
13795     (write-buffered *(ebp+0x10) "fn ")
13796     8b/-> *(ebp+0xc) 0/r32/eax
13797     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13798     (write-buffered *(ebp+0x10) %eax)
13799     (write-buffered *(ebp+0x10) ": stmt index: second argument '")
13800     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
13801     (write-buffered *(ebp+0x10) %eax)
13802     (write-buffered *(ebp+0x10) "' must be in a register\n")
13803     (flush *(ebp+0x10))
13804     (stop *(ebp+0x14) 1)
13805     # never gets here
13806 
13807 $check-mu-index-stmt:error-index-needs-offset:
13808     (write-buffered *(ebp+0x10) "fn ")
13809     8b/-> *(ebp+0xc) 0/r32/eax
13810     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13811     (write-buffered *(ebp+0x10) %eax)
13812     (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
13813     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13814     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13815     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13816     (write-buffered *(ebp+0x10) %eax)
13817     (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
13818     (flush *(ebp+0x10))
13819     (stop *(ebp+0x14) 1)
13820     # never gets here
13821 
13822 $check-mu-index-stmt:error-too-many-inouts:
13823     (write-buffered *(ebp+0x10) "fn ")
13824     8b/-> *(ebp+0xc) 0/r32/eax
13825     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13826     (write-buffered *(ebp+0x10) %eax)
13827     (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n")
13828     (flush *(ebp+0x10))
13829     (stop *(ebp+0x14) 1)
13830     # never gets here
13831 
13832 $check-mu-index-stmt:error-too-few-outputs:
13833     (write-buffered *(ebp+0x10) "fn ")
13834     8b/-> *(ebp+0xc) 0/r32/eax
13835     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13836     (write-buffered *(ebp+0x10) %eax)
13837     (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
13838     (flush *(ebp+0x10))
13839     (stop *(ebp+0x14) 1)
13840     # never gets here
13841 
13842 $check-mu-index-stmt:error-too-many-outputs:
13843     (write-buffered *(ebp+0x10) "fn ")
13844     8b/-> *(ebp+0xc) 0/r32/eax
13845     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13846     (write-buffered *(ebp+0x10) %eax)
13847     (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
13848     (flush *(ebp+0x10))
13849     (stop *(ebp+0x14) 1)
13850     # never gets here
13851 
13852 $check-mu-index-stmt:error-output-not-in-register:
13853     (write-buffered *(ebp+0x10) "fn ")
13854     8b/-> *(ebp+0xc) 0/r32/eax
13855     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13856     (write-buffered *(ebp+0x10) %eax)
13857     (write-buffered *(ebp+0x10) ": stmt index: output '")
13858     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13859     (write-buffered *(ebp+0x10) %eax)
13860     (write-buffered *(ebp+0x10) "' is not in a register\n")
13861     (flush *(ebp+0x10))
13862     (stop *(ebp+0x14) 1)
13863     # never gets here
13864 
13865 $check-mu-index-stmt:error-output-type-not-address:
13866     (write-buffered *(ebp+0x10) "fn ")
13867     8b/-> *(ebp+0xc) 0/r32/eax
13868     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13869     (write-buffered *(ebp+0x10) %eax)
13870     (write-buffered *(ebp+0x10) ": stmt index: output '")
13871     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13872     (write-buffered *(ebp+0x10) %eax)
13873     (write-buffered *(ebp+0x10) "' must be an address\n")
13874     (flush *(ebp+0x10))
13875     (stop *(ebp+0x14) 1)
13876     # never gets here
13877 
13878 $check-mu-index-stmt:error-bad-output-type:
13879     (write-buffered *(ebp+0x10) "fn ")
13880     8b/-> *(ebp+0xc) 0/r32/eax
13881     (lookup *eax *(eax+4))  # Function-name Function-name => eax
13882     (write-buffered *(ebp+0x10) %eax)
13883     (write-buffered *(ebp+0x10) ": stmt index: output '")
13884     (lookup *edi *(edi+4))  # Var-name Var-name => eax
13885     (write-buffered *(ebp+0x10) %eax)
13886     (write-buffered *(ebp+0x10) "' does not have the right type\n")
13887     (flush *(ebp+0x10))
13888     (stop *(ebp+0x14) 1)
13889     # never gets here
13890 
13891 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13892     # . prologue
13893     55/push-ebp
13894     89/<- %ebp 4/r32/esp
13895     # . save registers
13896 $check-mu-length-stmt:end:
13897     # . restore registers
13898     # . epilogue
13899     89/<- %esp 5/r32/ebp
13900     5d/pop-to-ebp
13901     c3/return
13902 
13903 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13904     # . prologue
13905     55/push-ebp
13906     89/<- %ebp 4/r32/esp
13907     # . save registers
13908 $check-mu-compute-offset-stmt:end:
13909     # . restore registers
13910     # . epilogue
13911     89/<- %esp 5/r32/ebp
13912     5d/pop-to-ebp
13913     c3/return
13914 
13915 check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13916     # . prologue
13917     55/push-ebp
13918     89/<- %ebp 4/r32/esp
13919     # . save registers
13920 $check-mu-copy-object-stmt:end:
13921     # . restore registers
13922     # . epilogue
13923     89/<- %esp 5/r32/ebp
13924     5d/pop-to-ebp
13925     c3/return
13926 
13927 check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13928     # . prologue
13929     55/push-ebp
13930     89/<- %ebp 4/r32/esp
13931     # . save registers
13932 $check-mu-allocate-stmt:end:
13933     # . restore registers
13934     # . epilogue
13935     89/<- %esp 5/r32/ebp
13936     5d/pop-to-ebp
13937     c3/return
13938 
13939 check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13940     # . prologue
13941     55/push-ebp
13942     89/<- %ebp 4/r32/esp
13943     # . save registers
13944 $check-mu-populate-stmt:end:
13945     # . restore registers
13946     # . epilogue
13947     89/<- %esp 5/r32/ebp
13948     5d/pop-to-ebp
13949     c3/return
13950 
13951 check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13952     # . prologue
13953     55/push-ebp
13954     89/<- %ebp 4/r32/esp
13955     # . save registers
13956 $check-mu-populate-stream-stmt:end:
13957     # . restore registers
13958     # . epilogue
13959     89/<- %esp 5/r32/ebp
13960     5d/pop-to-ebp
13961     c3/return
13962 
13963 check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13964     # . prologue
13965     55/push-ebp
13966     89/<- %ebp 4/r32/esp
13967     # . save registers
13968 $check-mu-read-from-stream-stmt:end:
13969     # . restore registers
13970     # . epilogue
13971     89/<- %esp 5/r32/ebp
13972     5d/pop-to-ebp
13973     c3/return
13974 
13975 check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13976     # . prologue
13977     55/push-ebp
13978     89/<- %ebp 4/r32/esp
13979     # . save registers
13980 $check-mu-write-to-stream-stmt:end:
13981     # . restore registers
13982     # . epilogue
13983     89/<- %esp 5/r32/ebp
13984     5d/pop-to-ebp
13985     c3/return
13986 
13987 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
13988     # . prologue
13989     55/push-ebp
13990     89/<- %ebp 4/r32/esp
13991     # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
13992     68/push 0/imm32
13993     # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
13994     81 5/subop/subtract %esp 0x60/imm32
13995     68/push 0x60/imm32/size
13996     68/push 0/imm32/read
13997     68/push 0/imm32/write
13998     # save a pointer to type-parameters-storage at type-parameters
13999     89/<- *(ebp-4) 4/r32/esp
14000     (clear-stream *(ebp-4))
14001     # . save registers
14002     50/push-eax
14003     51/push-ecx
14004     52/push-edx
14005     53/push-ebx
14006     56/push-esi
14007     57/push-edi
14008     # esi = stmt
14009     8b/-> *(ebp+8) 6/r32/esi
14010     # edi = callee
14011     8b/-> *(ebp+0xc) 7/r32/edi
14012     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
14013     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14014     89/<- %ecx 0/r32/eax
14015     # var expected/edx: (addr list var) = lookup(f->inouts)
14016     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
14017     89/<- %edx 0/r32/eax
14018     {
14019 $check-mu-call:check-for-inouts:
14020       # if (inouts == 0) break
14021       81 7/subop/compare %ecx 0/imm32
14022       0f 84/jump-if-= break/disp32
14023       # if (expected == 0) error
14024       81 7/subop/compare %edx 0/imm32
14025       0f 84/jump-if-= break/disp32
14026 $check-mu-call:check-inout-type:
14027       # var v/eax: (addr v) = lookup(inouts->value)
14028       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14029       # var t/ebx: (addr type-tree) = lookup(v->type)
14030       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14031       89/<- %ebx 0/r32/eax
14032       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
14033       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14034       {
14035         74/jump-if-= break/disp8
14036         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
14037         89/<- %ebx 0/r32/eax
14038         # if t->right is null, t = t->left
14039         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
14040         75/jump-if-!= break/disp8
14041         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
14042         89/<- %ebx 0/r32/eax
14043       }
14044       # var v2/eax: (addr v) = lookup(expected->value)
14045       (lookup *edx *(edx+4))  # List-value List-value => eax
14046       # var t2/eax: (addr type-tree) = lookup(v2->type)
14047       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14048       # if (t != t2) error
14049       (type-match? %eax %ebx *(ebp-4))  # => eax
14050       3d/compare-eax-and 0/imm32/false
14051       {
14052         0f 85/jump-if-!= break/disp32
14053         (write-buffered *(ebp+0x14) "fn ")
14054         8b/-> *(ebp+0x10) 0/r32/eax
14055         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14056         (write-buffered *(ebp+0x14) %eax)
14057         (write-buffered *(ebp+0x14) ": call ")
14058         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14059         (write-buffered *(ebp+0x14) %eax)
14060         (write-buffered *(ebp+0x14) ": type for inout '")
14061         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14062         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14063         (write-buffered *(ebp+0x14) %eax)
14064         (write-buffered *(ebp+0x14) "' is not right\n")
14065         (flush *(ebp+0x14))
14066         (stop *(ebp+0x18) 1)
14067       }
14068 $check-mu-call:continue-to-next-inout:
14069       # inouts = lookup(inouts->next)
14070       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14071       89/<- %ecx 0/r32/eax
14072       # expected = lookup(expected->next)
14073       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14074       89/<- %edx 0/r32/eax
14075       #
14076       e9/jump loop/disp32
14077     }
14078 $check-mu-call:check-inout-count:
14079     # if (inouts == expected) proceed
14080     39/compare %ecx 2/r32/edx
14081     {
14082       0f 84/jump-if-= break/disp32
14083       # exactly one of the two is null
14084       # if (inouts == 0) error("too many inouts")
14085       {
14086         81 7/subop/compare %ecx 0/imm32
14087         0f 84/jump-if-= break/disp32
14088         (write-buffered *(ebp+0x14) "fn ")
14089         8b/-> *(ebp+0x10) 0/r32/eax
14090         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14091         (write-buffered *(ebp+0x14) %eax)
14092         (write-buffered *(ebp+0x14) ": call ")
14093         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14094         (write-buffered *(ebp+0x14) %eax)
14095         (write-buffered *(ebp+0x14) ": too many inouts\n")
14096         (flush *(ebp+0x14))
14097         (stop *(ebp+0x18) 1)
14098       }
14099       # if (expected == 0) error("too few inouts")
14100       {
14101         81 7/subop/compare %edx 0/imm32
14102         0f 84/jump-if-= break/disp32
14103         (write-buffered *(ebp+0x14) "fn ")
14104         8b/-> *(ebp+0x10) 0/r32/eax
14105         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14106         (write-buffered *(ebp+0x14) %eax)
14107         (write-buffered *(ebp+0x14) ": call ")
14108         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14109         (write-buffered *(ebp+0x14) %eax)
14110         (write-buffered *(ebp+0x14) ": too few inouts\n")
14111         (flush *(ebp+0x14))
14112         (stop *(ebp+0x18) 1)
14113       }
14114     }
14115 $check-mu-call:check-outputs:
14116     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
14117     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14118     89/<- %ecx 0/r32/eax
14119     # var expected/edx: (addr list var) = lookup(f->outputs)
14120     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
14121     89/<- %edx 0/r32/eax
14122     {
14123 $check-mu-call:check-for-outputs:
14124       # if (outputs == 0) break
14125       81 7/subop/compare %ecx 0/imm32
14126       0f 84/jump-if-= break/disp32
14127       # if (expected == 0) error
14128       81 7/subop/compare %edx 0/imm32
14129       0f 84/jump-if-= break/disp32
14130 $check-mu-call:check-output-type:
14131       # var v/eax: (addr v) = lookup(outputs->value)
14132       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14133       # var t/ebx: (addr type-tree) = lookup(v->type)
14134       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14135       89/<- %ebx 0/r32/eax
14136       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
14137       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14138       {
14139         74/jump-if-= break/disp8
14140         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
14141         89/<- %ebx 0/r32/eax
14142       }
14143       # var v2/eax: (addr v) = lookup(expected->value)
14144       (lookup *edx *(edx+4))  # List-value List-value => eax
14145       # var t2/eax: (addr type-tree) = lookup(v2->type)
14146       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14147       # if (t != t2) error
14148       (type-match? %eax %ebx *(ebp-4))  # => eax
14149       3d/compare-eax-and 0/imm32/false
14150       {
14151         0f 85/jump-if-!= break/disp32
14152         (write-buffered *(ebp+0x14) "fn ")
14153         8b/-> *(ebp+0x10) 0/r32/eax
14154         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14155         (write-buffered *(ebp+0x14) %eax)
14156         (write-buffered *(ebp+0x14) ": call ")
14157         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14158         (write-buffered *(ebp+0x14) %eax)
14159         (write-buffered *(ebp+0x14) ": type for output '")
14160         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14161         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14162         (write-buffered *(ebp+0x14) %eax)
14163         (write-buffered *(ebp+0x14) "' is not right\n")
14164         (flush *(ebp+0x14))
14165         (stop *(ebp+0x18) 1)
14166       }
14167 $check-mu-call:check-output-register:
14168       # var v/eax: (addr v) = lookup(outputs->value)
14169       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14170       # var r/ebx: (addr array byte) = lookup(v->register)
14171       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14172       89/<- %ebx 0/r32/eax
14173       # if (r == 0) error
14174       3d/compare-eax-and 0/imm32
14175       {
14176         0f 85/jump-if-!= break/disp32
14177         (write-buffered *(ebp+0x14) "fn ")
14178         8b/-> *(ebp+0x10) 0/r32/eax
14179         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14180         (write-buffered *(ebp+0x14) %eax)
14181         (write-buffered *(ebp+0x14) ": call ")
14182         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14183         (write-buffered *(ebp+0x14) %eax)
14184         (write-buffered *(ebp+0x14) ": output '")
14185         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14186         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14187         (write-buffered *(ebp+0x14) %eax)
14188         (write-buffered *(ebp+0x14) "' is not in a register\n")
14189         (flush *(ebp+0x14))
14190         (stop *(ebp+0x18) 1)
14191       }
14192       # var v2/eax: (addr v) = lookup(expected->value)
14193       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
14194       # var r2/eax: (addr array byte) = lookup(v2->register)
14195       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
14196       # if (r != r2) error
14197       (string-equal? %eax %ebx)  # => eax
14198       3d/compare-eax-and 0/imm32/false
14199       {
14200         0f 85/jump-if-!= break/disp32
14201         (write-buffered *(ebp+0x14) "fn ")
14202         8b/-> *(ebp+0x10) 0/r32/eax
14203         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14204         (write-buffered *(ebp+0x14) %eax)
14205         (write-buffered *(ebp+0x14) ": call ")
14206         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14207         (write-buffered *(ebp+0x14) %eax)
14208         (write-buffered *(ebp+0x14) ": register for output '")
14209         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14210         (lookup *eax *(eax+4))  # Var-name Var-name => eax
14211         (write-buffered *(ebp+0x14) %eax)
14212         (write-buffered *(ebp+0x14) "' is not right\n")
14213         (flush *(ebp+0x14))
14214         (stop *(ebp+0x18) 1)
14215       }
14216 $check-mu-call:continue-to-next-output:
14217       # outputs = lookup(outputs->next)
14218       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
14219       89/<- %ecx 0/r32/eax
14220       # expected = lookup(expected->next)
14221       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
14222       89/<- %edx 0/r32/eax
14223       #
14224       e9/jump loop/disp32
14225     }
14226 $check-mu-call:check-output-count:
14227     # if (outputs == expected) proceed
14228     39/compare %ecx 2/r32/edx
14229     {
14230       0f 84/jump-if-= break/disp32
14231       # exactly one of the two is null
14232       # if (outputs == 0) error("too many outputs")
14233       {
14234         81 7/subop/compare %ecx 0/imm32
14235         0f 84/jump-if-= break/disp32
14236         (write-buffered *(ebp+0x14) "fn ")
14237         8b/-> *(ebp+0x10) 0/r32/eax
14238         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14239         (write-buffered *(ebp+0x14) %eax)
14240         (write-buffered *(ebp+0x14) ": call ")
14241         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14242         (write-buffered *(ebp+0x14) %eax)
14243         (write-buffered *(ebp+0x14) ": too many outputs\n")
14244         (flush *(ebp+0x14))
14245         (stop *(ebp+0x18) 1)
14246       }
14247       # if (expected == 0) error("too few outputs")
14248       {
14249         81 7/subop/compare %edx 0/imm32
14250         0f 84/jump-if-= break/disp32
14251         (write-buffered *(ebp+0x14) "fn ")
14252         8b/-> *(ebp+0x10) 0/r32/eax
14253         (lookup *eax *(eax+4))  # Function-name Function-name => eax
14254         (write-buffered *(ebp+0x14) %eax)
14255         (write-buffered *(ebp+0x14) ": call ")
14256         (lookup *edi *(edi+4))  # Function-name Function-name => eax
14257         (write-buffered *(ebp+0x14) %eax)
14258         (write-buffered *(ebp+0x14) ": too few outputs\n")
14259         (flush *(ebp+0x14))
14260         (stop *(ebp+0x18) 1)
14261       }
14262     }
14263 $check-mu-call:end:
14264     # . restore registers
14265     5f/pop-to-edi
14266     5e/pop-to-esi
14267     5b/pop-to-ebx
14268     5a/pop-to-edx
14269     59/pop-to-ecx
14270     58/pop-to-eax
14271     # . reclaim locals exclusively on the stack
14272     81 0/subop/add %esp 0x70/imm32
14273     # . epilogue
14274     89/<- %esp 5/r32/ebp
14275     5d/pop-to-ebp
14276     c3/return
14277 
14278 # like type-equal? but takes literals into account
14279 type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14280     # . prologue
14281     55/push-ebp
14282     89/<- %ebp 4/r32/esp
14283     # if (call == literal) return true  # TODO: more precise
14284     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
14285     3d/compare-eax-and 0/imm32/false
14286     b8/copy-to-eax 1/imm32/true
14287     75/jump-if-!= $type-match?:end/disp8
14288 $type-match?:baseline:
14289     # otherwise fall back
14290     (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
14291 $type-match?:end:
14292     # . epilogue
14293     89/<- %esp 5/r32/ebp
14294     5d/pop-to-ebp
14295     c3/return
14296 
14297 type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
14298     # . prologue
14299     55/push-ebp
14300     89/<- %ebp 4/r32/esp
14301     # . save registers
14302     51/push-ecx
14303     52/push-edx
14304     53/push-ebx
14305     # ecx = def
14306     8b/-> *(ebp+8) 1/r32/ecx
14307     # edx = call
14308     8b/-> *(ebp+0xc) 2/r32/edx
14309 $type-component-match?:compare-addr:
14310     # if (def == call) return true
14311     8b/-> %ecx 0/r32/eax  # Var-type
14312     39/compare %edx 0/r32/eax  # Var-type
14313     b8/copy-to-eax 1/imm32/true
14314     0f 84/jump-if-= $type-component-match?:end/disp32
14315     # if (def == 0) return false
14316     b8/copy-to-eax 0/imm32/false
14317     81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
14318     0f 84/jump-if-= $type-component-match?:end/disp32
14319     # if (call == 0) return false
14320     81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
14321     0f 84/jump-if-= $type-component-match?:end/disp32
14322     # if def is a type parameter, just check in type-parameters
14323     {
14324 $type-component-match?:check-type-parameter:
14325       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14326       74/jump-if-= break/disp8
14327       81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
14328       75/jump-if-!= break/disp8
14329 $type-component-match?:type-parameter:
14330       (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
14331       e9/jump $type-component-match?:end/disp32
14332     }
14333     # if def is a list containing just a type parameter, just check in type-parameters
14334     {
14335 $type-component-match?:check-list-type-parameter:
14336       # if def is a list..
14337       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14338       75/jump-if-!= break/disp8
14339       #   ..that's a singleton
14340       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
14341       75/jump-if-!= break/disp8
14342       #   ..and whose head is a type parameter
14343       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14344       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14345       74/jump-if-= break/disp8
14346       81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
14347       75/jump-if-!= break/disp8
14348 $type-component-match?:list-type-parameter:
14349       (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
14350       e9/jump $type-component-match?:end/disp32
14351     }
14352 $type-component-match?:compare-atom-state:
14353     # if (def->is-atom? != call->is-atom?) return false
14354     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14355     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14356     b8/copy-to-eax 0/imm32/false
14357     0f 85/jump-if-!= $type-component-match?:end/disp32
14358     # if def->is-atom? return (def->value == call->value)
14359     {
14360 $type-component-match?:check-atom:
14361       81 7/subop/compare %ebx 0/imm32/false
14362       74/jump-if-= break/disp8
14363 $type-component-match?:is-atom:
14364       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14365       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14366       0f 94/set-if-= %al
14367       81 4/subop/and %eax 0xff/imm32
14368       e9/jump $type-component-match?:end/disp32
14369     }
14370 $type-component-match?:check-left:
14371     # if (!type-component-match?(def->left, call->left)) return false
14372     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14373     89/<- %ebx 0/r32/eax
14374     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14375     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14376     3d/compare-eax-and 0/imm32/false
14377     74/jump-if-= $type-component-match?:end/disp8
14378 $type-component-match?:check-right:
14379     # return type-component-match?(def->right, call->right)
14380     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14381     89/<- %ebx 0/r32/eax
14382     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14383     (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
14384 $type-component-match?:end:
14385     # . restore registers
14386     5b/pop-to-ebx
14387     5a/pop-to-edx
14388     59/pop-to-ecx
14389     # . epilogue
14390     89/<- %esp 5/r32/ebp
14391     5d/pop-to-ebp
14392     c3/return
14393 
14394 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
14395     # . prologue
14396     55/push-ebp
14397     89/<- %ebp 4/r32/esp
14398     # . save registers
14399     51/push-ecx
14400     #
14401     (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
14402     # if parameter wasn't saved, save it
14403     {
14404       81 7/subop/compare *eax 0/imm32
14405       75/jump-if-!= break/disp8
14406       8b/-> *(ebp+0x10) 1/r32/ecx
14407       89/<- *eax 1/r32/ecx
14408     }
14409     #
14410     (type-equal? *(ebp+0x10) *eax)  # => eax
14411 $type-parameter-match?:end:
14412     # . restore registers
14413     59/pop-to-ecx
14414     # . epilogue
14415     89/<- %esp 5/r32/ebp
14416     5d/pop-to-ebp
14417     c3/return
14418 
14419 size-of:  # v: (addr var) -> result/eax: int
14420     # . prologue
14421     55/push-ebp
14422     89/<- %ebp 4/r32/esp
14423     # . save registers
14424     51/push-ecx
14425     # var t/ecx: (addr type-tree) = lookup(v->type)
14426     8b/-> *(ebp+8) 1/r32/ecx
14427 #?     (write-buffered Stderr "size-of ")
14428 #?     (write-int32-hex-buffered Stderr %ecx)
14429 #?     (write-buffered Stderr Newline)
14430 #?     (write-buffered Stderr "type allocid: ")
14431 #?     (write-int32-hex-buffered Stderr *(ecx+8))
14432 #?     (write-buffered Stderr Newline)
14433 #?     (flush Stderr)
14434     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14435     89/<- %ecx 0/r32/eax
14436     # if is-mu-array?(t) return size-of-array(t)
14437     {
14438       (is-mu-array? %ecx)  # => eax
14439       3d/compare-eax-and 0/imm32/false
14440       74/jump-if-= break/disp8
14441       (size-of-array %ecx)  # => eax
14442       eb/jump $size-of:end/disp8
14443     }
14444     # if is-mu-stream?(t) return size-of-stream(t)
14445     {
14446       (is-mu-stream? %ecx)  # => eax
14447       3d/compare-eax-and 0/imm32/false
14448       74/jump-if-= break/disp8
14449       (size-of-stream %ecx)  # => eax
14450       eb/jump $size-of:end/disp8
14451     }
14452     # if (!t->is-atom?) t = lookup(t->left)
14453     {
14454       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14455       75/jump-if-!= break/disp8
14456       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14457       89/<- %ecx 0/r32/eax
14458     }
14459     # TODO: assert t->is-atom?
14460     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14461 $size-of:end:
14462     # . restore registers
14463     59/pop-to-ecx
14464     # . epilogue
14465     89/<- %esp 5/r32/ebp
14466     5d/pop-to-ebp
14467     c3/return
14468 
14469 size-of-deref:  # v: (addr var) -> result/eax: int
14470     # . prologue
14471     55/push-ebp
14472     89/<- %ebp 4/r32/esp
14473     # . save registers
14474     51/push-ecx
14475     # var t/ecx: (addr type-tree) = lookup(v->type)
14476     8b/-> *(ebp+8) 1/r32/ecx
14477     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
14478     89/<- %ecx 0/r32/eax
14479     # TODO: assert(t is an addr)
14480     # t = lookup(t->right)
14481     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14482     89/<- %ecx 0/r32/eax
14483     # if is-mu-array?(t) return size-of-array(t)
14484     {
14485       (is-mu-array? %ecx)  # => eax
14486       3d/compare-eax-and 0/imm32/false
14487       74/jump-if-= break/disp8
14488       (size-of-array %ecx)  # => eax
14489       eb/jump $size-of-deref:end/disp8
14490     }
14491     # if is-mu-stream?(t) return size-of-stream(t)
14492     {
14493       (is-mu-stream? %ecx)  # => eax
14494       3d/compare-eax-and 0/imm32/false
14495       74/jump-if-= break/disp8
14496       (size-of-stream %ecx)  # => eax
14497       eb/jump $size-of-deref:end/disp8
14498     }
14499     # if (!t->is-atom?) t = lookup(t->left)
14500     {
14501       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14502       75/jump-if-!= break/disp8
14503       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14504       89/<- %ecx 0/r32/eax
14505     }
14506     # TODO: assert t->is-atom?
14507     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
14508 $size-of-deref:end:
14509     # . restore registers
14510     59/pop-to-ecx
14511     # . epilogue
14512     89/<- %esp 5/r32/ebp
14513     5d/pop-to-ebp
14514     c3/return
14515 
14516 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
14517     # . prologue
14518     55/push-ebp
14519     89/<- %ebp 4/r32/esp
14520     # . save registers
14521     51/push-ecx
14522     # ecx = t
14523     8b/-> *(ebp+8) 1/r32/ecx
14524     # if t->is-atom?, return false
14525     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14526     75/jump-if-!= $is-mu-array?:return-false/disp8
14527     # if !t->left->is-atom?, return false
14528     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14529     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14530     74/jump-if-= $is-mu-array?:return-false/disp8
14531     # return t->left->value == array
14532     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
14533     0f 94/set-if-= %al
14534     81 4/subop/and %eax 0xff/imm32
14535     eb/jump $is-mu-array?:end/disp8
14536 $is-mu-array?:return-false:
14537     b8/copy-to-eax 0/imm32/false
14538 $is-mu-array?:end:
14539     # . restore registers
14540     59/pop-to-ecx
14541     # . epilogue
14542     89/<- %esp 5/r32/ebp
14543     5d/pop-to-ebp
14544     c3/return
14545 
14546 # size of a statically allocated array where the size is part of the type expression
14547 size-of-array:  # a: (addr type-tree) -> result/eax: int
14548     # . prologue
14549     55/push-ebp
14550     89/<- %ebp 4/r32/esp
14551     # . save registers
14552     51/push-ecx
14553     52/push-edx
14554     #
14555     8b/-> *(ebp+8) 1/r32/ecx
14556     # TODO: assert that a->left is 'array'
14557     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14558     89/<- %ecx 0/r32/eax
14559     # var elem-type/edx: type-id = a->right->left->value
14560     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14561     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
14562     # TODO: assert that a->right->right->left->value == size
14563     # var array-size/ecx: int = a->right->right->left->value-size
14564     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14565     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14566     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
14567     # return 4 + array-size * size-of(elem-type)
14568     (size-of-type-id-as-array-element %edx)  # => eax
14569     f7 4/subop/multiply-into-edx-eax %ecx
14570     05/add-to-eax 4/imm32  # for array size
14571     # TODO: check edx for overflow
14572 $size-of-array:end:
14573     # . restore registers
14574     5a/pop-to-edx
14575     59/pop-to-ecx
14576     # . epilogue
14577     89/<- %esp 5/r32/ebp
14578     5d/pop-to-ebp
14579     c3/return
14580 
14581 is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
14582     # . prologue
14583     55/push-ebp
14584     89/<- %ebp 4/r32/esp
14585     # . save registers
14586     51/push-ecx
14587     # ecx = t
14588     8b/-> *(ebp+8) 1/r32/ecx
14589     # if t->is-atom?, return false
14590     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14591     75/jump-if-!= $is-mu-stream?:return-false/disp8
14592     # if !t->left->is-atom?, return false
14593     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14594     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14595     74/jump-if-= $is-mu-stream?:return-false/disp8
14596     # return t->left->value == stream
14597     81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
14598     0f 94/set-if-= %al
14599     81 4/subop/and %eax 0xff/imm32
14600     eb/jump $is-mu-stream?:end/disp8
14601 $is-mu-stream?:return-false:
14602     b8/copy-to-eax 0/imm32/false
14603 $is-mu-stream?:end:
14604     # . restore registers
14605     59/pop-to-ecx
14606     # . epilogue
14607     89/<- %esp 5/r32/ebp
14608     5d/pop-to-ebp
14609     c3/return
14610 
14611 # size of a statically allocated stream where the size is part of the type expression
14612 size-of-stream:  # a: (addr type-tree) -> result/eax: int
14613     # . prologue
14614     55/push-ebp
14615     89/<- %ebp 4/r32/esp
14616     #
14617     (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
14618     05/add-to-eax 8/imm32  # for read/write pointers
14619 $size-of-stream:end:
14620     # . epilogue
14621     89/<- %esp 5/r32/ebp
14622     5d/pop-to-ebp
14623     c3/return
14624 
14625 size-of-type-id:  # t: type-id -> result/eax: int
14626     # . prologue
14627     55/push-ebp
14628     89/<- %ebp 4/r32/esp
14629     # . save registers
14630     51/push-ecx
14631     # var out/ecx: (handle typeinfo)
14632     68/push 0/imm32
14633     68/push 0/imm32
14634     89/<- %ecx 4/r32/esp
14635     # eax = t
14636     8b/-> *(ebp+8) 0/r32/eax
14637     # if t is a literal, return 0
14638     3d/compare-eax-and 0/imm32
14639     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
14640     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
14641     3d/compare-eax-and 8/imm32/byte
14642     {
14643       75/jump-if-!= break/disp8
14644       b8/copy-to-eax 4/imm32
14645       eb/jump $size-of-type-id:end/disp8
14646     }
14647     # if t is a handle, return 8
14648     3d/compare-eax-and 4/imm32/handle
14649     {
14650       75/jump-if-!= break/disp8
14651       b8/copy-to-eax 8/imm32
14652       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
14653     }
14654     # if t is a slice, return 8
14655     3d/compare-eax-and 0xc/imm32/slice
14656     {
14657       75/jump-if-!= break/disp8
14658       b8/copy-to-eax 8/imm32
14659       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
14660     }
14661     # if t is a user-defined type, return its size
14662     # TODO: support non-atom type
14663     (find-typeinfo %eax %ecx)
14664     {
14665       81 7/subop/compare *ecx 0/imm32
14666       74/jump-if-= break/disp8
14667 $size-of-type-id:user-defined:
14668       (lookup *ecx *(ecx+4))  # => eax
14669       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
14670       eb/jump $size-of-type-id:end/disp8
14671     }
14672     # otherwise return the word size
14673     b8/copy-to-eax 4/imm32
14674 $size-of-type-id:end:
14675     # . reclaim locals
14676     81 0/subop/add %esp 8/imm32
14677     # . restore registers
14678     59/pop-to-ecx
14679     # . epilogue
14680     89/<- %esp 5/r32/ebp
14681     5d/pop-to-ebp
14682     c3/return
14683 
14684 # Minor violation of our type system since it returns an addr. But we could
14685 # replace it with a handle some time.
14686 # Returns null if t is an atom.
14687 type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
14688     # . prologue
14689     55/push-ebp
14690     89/<- %ebp 4/r32/esp
14691     # . save registers
14692     51/push-ecx
14693     # eax = 0
14694     b8/copy-to-eax 0/imm32
14695     # ecx = t
14696     8b/-> *(ebp+8) 1/r32/ecx
14697 $type-tail:check-atom:
14698     # if t->is-atom? return 0
14699     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
14700     0f 85/jump-if-!= $type-tail:end/disp32
14701     # var tail = t->right
14702     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14703     89/<- %ecx 0/r32/eax
14704 $type-tail:check-singleton:
14705     # if (tail->right == 0) return tail->left
14706     {
14707       81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
14708       75/jump-if-!= break/disp8
14709       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14710       e9/jump $type-tail:end/disp32
14711     }
14712     # if tail->right->left is an array-capacity, return tail->left
14713     {
14714 $type-tail:check-array-capacity:
14715       (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14716       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14717       75/jump-if-!= break/disp8
14718 $type-tail:check-array-capacity-1:
14719       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14720       3d/compare-eax-and 0/imm32
14721       74/jump-if-= break/disp8
14722 $type-tail:check-array-capacity-2:
14723       (is-simple-mu-type? %eax 9)  # array-capacity => eax
14724       3d/compare-eax-and 0/imm32/false
14725       74/jump-if-= break/disp8
14726 $type-tail:array-capacity:
14727       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14728       eb/jump $type-tail:end/disp8
14729     }
14730 $type-tail:check-compound-left:
14731     # if !tail->left->is-atom? return tail->left
14732     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14733     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14734     74/jump-if-= $type-tail:end/disp8
14735 $type-tail:return-tail:
14736     # return tail
14737     89/<- %eax 1/r32/ecx
14738 $type-tail:end:
14739     # . restore registers
14740     59/pop-to-ecx
14741     # . epilogue
14742     89/<- %esp 5/r32/ebp
14743     5d/pop-to-ebp
14744     c3/return
14745 
14746 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
14747     # . prologue
14748     55/push-ebp
14749     89/<- %ebp 4/r32/esp
14750     # . save registers
14751     51/push-ecx
14752     52/push-edx
14753     53/push-ebx
14754     # ecx = a
14755     8b/-> *(ebp+8) 1/r32/ecx
14756     # edx = b
14757     8b/-> *(ebp+0xc) 2/r32/edx
14758 $type-equal?:compare-addr:
14759     # if (a == b) return true
14760     8b/-> %ecx 0/r32/eax  # Var-type
14761     39/compare %edx 0/r32/eax  # Var-type
14762     b8/copy-to-eax 1/imm32/true
14763     0f 84/jump-if-= $type-equal?:end/disp32
14764 $type-equal?:compare-null-a:
14765     # if (a == 0) return false
14766     b8/copy-to-eax 0/imm32/false
14767     81 7/subop/compare %ecx 0/imm32
14768     0f 84/jump-if-= $type-equal?:end/disp32
14769 $type-equal?:compare-null-b:
14770     # if (b == 0) return false
14771     81 7/subop/compare %edx 0/imm32
14772     0f 84/jump-if-= $type-equal?:end/disp32
14773 $type-equal?:compare-atom-state:
14774     # if (a->is-atom? != b->is-atom?) return false
14775     8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
14776     39/compare *edx 3/r32/ebx  # Type-tree-is-atom
14777     b8/copy-to-eax 0/imm32/false
14778     0f 85/jump-if-!= $type-equal?:end/disp32
14779     # if a->is-atom? return (a->value == b->value)
14780     {
14781 $type-equal?:check-atom:
14782       81 7/subop/compare %ebx 0/imm32/false
14783       74/jump-if-= break/disp8
14784 $type-equal?:is-atom:
14785       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
14786       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
14787       0f 94/set-if-= %al
14788       81 4/subop/and %eax 0xff/imm32
14789       e9/jump $type-equal?:end/disp32
14790     }
14791 $type-equal?:check-left:
14792     # if (!type-equal?(a->left, b->left)) return false
14793     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
14794     89/<- %ebx 0/r32/eax
14795     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
14796     (type-equal? %eax %ebx)  # => eax
14797     3d/compare-eax-and 0/imm32/false
14798     74/jump-if-= $type-equal?:end/disp8
14799 $type-equal?:check-right:
14800     # return type-equal?(a->right, b->right)
14801     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
14802     89/<- %ebx 0/r32/eax
14803     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
14804     (type-equal? %eax %ebx)  # => eax
14805 $type-equal?:end:
14806     # . restore registers
14807     5b/pop-to-ebx
14808     5a/pop-to-edx
14809     59/pop-to-ecx
14810     # . epilogue
14811     89/<- %esp 5/r32/ebp
14812     5d/pop-to-ebp
14813     c3/return
14814 
14815 #######################################################
14816 # Code-generation
14817 #######################################################
14818 
14819 == data
14820 
14821 # Global state added to each var record when performing code-generation.
14822 Curr-local-stack-offset:  # (addr int)
14823     0/imm32
14824 
14825 == code
14826 
14827 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
14828     # . prologue
14829     55/push-ebp
14830     89/<- %ebp 4/r32/esp
14831     # . save registers
14832     50/push-eax
14833     # var curr/eax: (addr function) = *Program->functions
14834     (lookup *_Program-functions *_Program-functions->payload)  # => eax
14835     {
14836       # if (curr == null) break
14837       3d/compare-eax-and 0/imm32
14838       0f 84/jump-if-= break/disp32
14839       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
14840       # curr = lookup(curr->next)
14841       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
14842       e9/jump loop/disp32
14843     }
14844 $emit-subx:end:
14845     # . restore registers
14846     58/pop-to-eax
14847     # . epilogue
14848     89/<- %esp 5/r32/ebp
14849     5d/pop-to-ebp
14850     c3/return
14851 
14852 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14853     # . prologue
14854     55/push-ebp
14855     89/<- %ebp 4/r32/esp
14856     # some preprocessing
14857     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
14858     # . save registers
14859     50/push-eax
14860     51/push-ecx
14861     52/push-edx
14862     # initialize some global state
14863     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
14864     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
14865     # ecx = f
14866     8b/-> *(ebp+0xc) 1/r32/ecx
14867     # var vars/edx: (stack (addr var) 256)
14868     81 5/subop/subtract %esp 0xc00/imm32
14869     68/push 0xc00/imm32/size
14870     68/push 0/imm32/top
14871     89/<- %edx 4/r32/esp
14872     # var name/eax: (addr array byte) = lookup(f->name)
14873     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
14874     #
14875     (write-buffered *(ebp+8) %eax)
14876     (write-buffered *(ebp+8) ":\n")
14877     (emit-subx-prologue *(ebp+8))
14878     # var body/eax: (addr block) = lookup(f->body)
14879     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
14880     #
14881     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
14882     (emit-subx-epilogue *(ebp+8))
14883     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
14884     # been cleaned up
14885 $emit-subx-function:end:
14886     # . reclaim locals
14887     81 0/subop/add %esp 0xc08/imm32
14888     # . restore registers
14889     5a/pop-to-edx
14890     59/pop-to-ecx
14891     58/pop-to-eax
14892     # . epilogue
14893     89/<- %esp 5/r32/ebp
14894     5d/pop-to-ebp
14895     c3/return
14896 
14897 populate-mu-type-offsets-in-inouts:  # f: (addr function)
14898     # . prologue
14899     55/push-ebp
14900     89/<- %ebp 4/r32/esp
14901     # . save registers
14902     50/push-eax
14903     51/push-ecx
14904     52/push-edx
14905     53/push-ebx
14906     57/push-edi
14907     # var next-offset/edx: int = 8
14908     ba/copy-to-edx 8/imm32
14909     # var curr/ecx: (addr list var) = lookup(f->inouts)
14910     8b/-> *(ebp+8) 1/r32/ecx
14911     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
14912     89/<- %ecx 0/r32/eax
14913     {
14914 $populate-mu-type-offsets-in-inouts:loop:
14915       81 7/subop/compare %ecx 0/imm32
14916       74/jump-if-= break/disp8
14917       # var v/ebx: (addr var) = lookup(curr->value)
14918       (lookup *ecx *(ecx+4))  # List-value List-value => eax
14919       89/<- %ebx 0/r32/eax
14920 #?       (lookup *ebx *(ebx+4))
14921 #?       (write-buffered Stderr "setting offset of fn inout ")
14922 #?       (write-buffered Stderr %eax)
14923 #?       (write-buffered Stderr "@")
14924 #?       (write-int32-hex-buffered Stderr %ebx)
14925 #?       (write-buffered Stderr " to ")
14926 #?       (write-int32-hex-buffered Stderr %edx)
14927 #?       (write-buffered Stderr Newline)
14928 #?       (flush Stderr)
14929       # v->offset = next-offset
14930       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
14931       # next-offset += size-of(v)
14932       (size-of %ebx)  # => eax
14933       01/add-to %edx 0/r32/eax
14934       # curr = lookup(curr->next)
14935       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
14936       89/<- %ecx 0/r32/eax
14937       #
14938       eb/jump loop/disp8
14939     }
14940 $populate-mu-type-offsets-in-inouts:end:
14941     # . restore registers
14942     5f/pop-to-edi
14943     5b/pop-to-ebx
14944     5a/pop-to-edx
14945     59/pop-to-ecx
14946     58/pop-to-eax
14947     # . epilogue
14948     89/<- %esp 5/r32/ebp
14949     5d/pop-to-ebp
14950     c3/return
14951 
14952 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)
14953     # . prologue
14954     55/push-ebp
14955     89/<- %ebp 4/r32/esp
14956     # . save registers
14957     50/push-eax
14958     51/push-ecx
14959     53/push-ebx
14960     56/push-esi
14961     # esi = stmts
14962     8b/-> *(ebp+0xc) 6/r32/esi
14963     #
14964     {
14965 $emit-subx-stmt-list:loop:
14966       81 7/subop/compare %esi 0/imm32
14967       0f 84/jump-if-= break/disp32
14968       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
14969       (lookup *esi *(esi+4))  # List-value List-value => eax
14970       89/<- %ecx 0/r32/eax
14971       {
14972 $emit-subx-stmt-list:check-for-block:
14973         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
14974         75/jump-if-!= break/disp8
14975 $emit-subx-stmt-list:block:
14976         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14977       }
14978       {
14979 $emit-subx-stmt-list:check-for-stmt:
14980         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
14981         0f 85/jump-if-!= break/disp32
14982 $emit-subx-stmt-list:stmt1:
14983         {
14984           (is-mu-branch? %ecx)  # => eax
14985           3d/compare-eax-and 0/imm32/false
14986           0f 84/jump-if-= break/disp32
14987 $emit-subx-stmt-list:branch-stmt:
14988 +-- 27 lines: # unconditional loops --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15015 +-- 16 lines: # unconditional breaks -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
15031 +-- 38 lines: # simple conditional branches without a target -------------------------------------------------------------------------------------------------------------------------------------------------------
15069 +-- 19 lines: # conditional branches with an explicit target -------------------------------------------------------------------------------------------------------------------------------------------------------
15088         }
15089 $emit-subx-stmt-list:1-to-1:
15090         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
15091         e9/jump $emit-subx-stmt-list:continue/disp32
15092       }
15093       {
15094 $emit-subx-stmt-list:check-for-var-def:
15095         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
15096         75/jump-if-!= break/disp8
15097 $emit-subx-stmt-list:var-def:
15098         (emit-subx-var-def *(ebp+8) %ecx)
15099         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
15100         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
15101         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
15102         #
15103         eb/jump $emit-subx-stmt-list:continue/disp8
15104       }
15105       {
15106 $emit-subx-stmt-list:check-for-reg-var-def:
15107         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
15108         0f 85/jump-if-!= break/disp32
15109 $emit-subx-stmt-list:reg-var-def:
15110         # TODO: ensure that there's exactly one output
15111         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
15112         # emit the instruction as usual
15113         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
15114         #
15115         eb/jump $emit-subx-stmt-list:continue/disp8
15116       }
15117 $emit-subx-stmt-list:continue:
15118       # TODO: raise an error on unrecognized Stmt-tag
15119       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
15120       89/<- %esi 0/r32/eax
15121       e9/jump loop/disp32
15122     }
15123 $emit-subx-stmt-list:emit-cleanup:
15124     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
15125 $emit-subx-stmt-list:clean-up:
15126     (clean-up-stack-offset-state *(ebp+0x10) *Curr-block-depth)
15127     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
15128 $emit-subx-stmt-list:end:
15129     # . restore registers
15130     5e/pop-to-esi
15131     5b/pop-to-ebx
15132     59/pop-to-ecx
15133     58/pop-to-eax
15134     # . epilogue
15135     89/<- %esp 5/r32/ebp
15136     5d/pop-to-ebp
15137     c3/return
15138 
15139 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
15140 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)
15141     # . prologue
15142     55/push-ebp
15143     89/<- %ebp 4/r32/esp
15144     # . save registers
15145     50/push-eax
15146     51/push-ecx
15147     52/push-edx
15148     # ecx = stmt
15149     8b/-> *(ebp+0xc) 1/r32/ecx
15150     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
15151     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15152     # TODO: assert !sv->is-deref?
15153     # var v/ecx: (addr var) = lookup(sv->value)
15154     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15155     89/<- %ecx 0/r32/eax
15156     # v->block-depth = *Curr-block-depth
15157     8b/-> *Curr-block-depth 0/r32/eax
15158     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
15159 #?     (write-buffered Stderr "var ")
15160 #?     (lookup *ecx *(ecx+4))
15161 #?     (write-buffered Stderr %eax)
15162 #?     (write-buffered Stderr " at depth ")
15163 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
15164 #?     (write-buffered Stderr Newline)
15165 #?     (flush Stderr)
15166     # ensure that v is in a register
15167     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
15168     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
15169     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
15170     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
15171     89/<- %edx 0/r32/eax
15172     3d/compare-eax-and 0/imm32/false
15173     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15174     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
15175     89/<- %edx 0/r32/eax
15176     # check emit-spill?
15177     3d/compare-eax-and 0/imm32/false
15178     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
15179     # TODO: assert(size-of(output) == 4)
15180     # *Curr-local-stack-offset -= 4
15181     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
15182     # emit spill
15183     (emit-indent *(ebp+8) *Curr-block-depth)
15184     (write-buffered *(ebp+8) "ff 6/subop/push %")
15185     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15186     (write-buffered *(ebp+8) %eax)
15187     (write-buffered *(ebp+8) Newline)
15188 $push-output-and-maybe-emit-spill:push:
15189     8b/-> *(ebp+0xc) 1/r32/ecx
15190     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
15191     # push(vars, {sv->value, emit-spill?})
15192     (push *(ebp+0x10) *eax)  # Stmt-var-value
15193     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
15194     (push *(ebp+0x10) %edx)
15195 $push-output-and-maybe-emit-spill:end:
15196     # . restore registers
15197     5a/pop-to-edx
15198     59/pop-to-ecx
15199     58/pop-to-eax
15200     # . epilogue
15201     89/<- %esp 5/r32/ebp
15202     5d/pop-to-ebp
15203     c3/return
15204 
15205 $push-output-and-maybe-emit-spill:abort:
15206     # error("var '" var->name "' initialized from an instruction must live in a register\n")
15207     (write-buffered *(ebp+0x1c) "var '")
15208     (write-buffered *(ebp+0x1c) *eax)  # Var-name
15209     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
15210     (flush *(ebp+0x1c))
15211     (stop *(ebp+0x20) 1)
15212     # never gets here
15213 
15214 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
15215     # . prologue
15216     55/push-ebp
15217     89/<- %ebp 4/r32/esp
15218     # . save registers
15219     50/push-eax
15220     51/push-ecx
15221     # ecx = stmt
15222     8b/-> *(ebp+0xc) 1/r32/ecx
15223     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
15224     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15225     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15226     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15227     # clean up until target block
15228     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
15229     # emit jump to target block
15230     (emit-indent *(ebp+8) *Curr-block-depth)
15231     (write-buffered *(ebp+8) "e9/jump ")
15232     (write-buffered *(ebp+8) %eax)
15233     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15234     (string-starts-with? %eax "break")
15235     3d/compare-eax-and 0/imm32/false
15236     {
15237       74/jump-if-= break/disp8
15238       (write-buffered *(ebp+8) ":break/disp32\n")
15239     }
15240     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
15241     {
15242       75/jump-if-!= break/disp8
15243       (write-buffered *(ebp+8) ":loop/disp32\n")
15244     }
15245 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
15246     # . restore registers
15247     59/pop-to-ecx
15248     58/pop-to-eax
15249     # . epilogue
15250     89/<- %esp 5/r32/ebp
15251     5d/pop-to-ebp
15252     c3/return
15253 
15254 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
15255     # . prologue
15256     55/push-ebp
15257     89/<- %ebp 4/r32/esp
15258     # . save registers
15259     51/push-ecx
15260     # ecx = lookup(stmt->operation)
15261     8b/-> *(ebp+8) 1/r32/ecx
15262     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15263     89/<- %ecx 0/r32/eax
15264     # if (stmt->operation starts with "loop") return true
15265     (string-starts-with? %ecx "loop")  # => eax
15266     3d/compare-eax-and 0/imm32/false
15267     75/jump-if-not-equal $is-mu-branch?:end/disp8
15268     # otherwise return (stmt->operation starts with "break")
15269     (string-starts-with? %ecx "break")  # => eax
15270 $is-mu-branch?:end:
15271     # . restore registers
15272     59/pop-to-ecx
15273     # . epilogue
15274     89/<- %esp 5/r32/ebp
15275     5d/pop-to-ebp
15276     c3/return
15277 
15278 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
15279     # . prologue
15280     55/push-ebp
15281     89/<- %ebp 4/r32/esp
15282     # . save registers
15283     50/push-eax
15284     # eax = stmt
15285     8b/-> *(ebp+0xc) 0/r32/eax
15286     #
15287     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15288     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
15289     (emit-indent *(ebp+8) *Curr-block-depth)
15290     (lookup *eax *(eax+4))  # => eax
15291     (write-buffered *(ebp+8) %eax)
15292     (write-buffered *(ebp+8) " break/disp32\n")
15293 $emit-reverse-break:end:
15294     # . restore registers
15295     58/pop-to-eax
15296     # . epilogue
15297     89/<- %esp 5/r32/ebp
15298     5d/pop-to-ebp
15299     c3/return
15300 
15301 == data
15302 
15303 # Table from Mu branch instructions to the reverse SubX opcodes for them.
15304 Reverse-branch:  # (table (handle array byte) (handle array byte))
15305   # a table is a stream
15306   0x140/imm32/write
15307   0/imm32/read
15308   0x140/imm32/size
15309   # data
15310   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15311   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
15312   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15313   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
15314   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15315   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
15316   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15317   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
15318   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15319   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15320   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15321   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
15322   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15323   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
15324   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15325   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
15326   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15327   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
15328   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15329   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
15330 
15331 == code
15332 
15333 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
15334     # . prologue
15335     55/push-ebp
15336     89/<- %ebp 4/r32/esp
15337     # . save registers
15338     50/push-eax
15339     51/push-ecx
15340     52/push-edx
15341     53/push-ebx
15342     56/push-esi
15343     # ecx = vars
15344     8b/-> *(ebp+0xc) 1/r32/ecx
15345     # var eax: int = vars->top
15346     8b/-> *ecx 0/r32/eax
15347     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15348     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15349     # var min/ecx: (addr handle var) = vars->data
15350     8d/copy-address *(ecx+8) 1/r32/ecx
15351     # edx = depth
15352     8b/-> *(ebp+0x10) 2/r32/edx
15353     {
15354 $emit-unconditional-jump-to-depth:loop:
15355       # if (curr < min) break
15356       39/compare %esi 1/r32/ecx
15357       0f 82/jump-if-addr< break/disp32
15358       # var v/ebx: (addr var) = lookup(*curr)
15359       (lookup *esi *(esi+4))  # => eax
15360       89/<- %ebx 0/r32/eax
15361       # if (v->block-depth < until-block-depth) break
15362       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15363       0f 8c/jump-if-< break/disp32
15364       {
15365 $emit-unconditional-jump-to-depth:check:
15366         # if v->block-depth != until-block-depth, continue
15367         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15368         0f 85/jump-if-!= break/disp32
15369 $emit-unconditional-jump-to-depth:depth-found:
15370         # if v is not a literal, continue
15371         (size-of %ebx)  # => eax
15372         3d/compare-eax-and 0/imm32
15373         0f 85/jump-if-!= break/disp32
15374 $emit-unconditional-jump-to-depth:label-found:
15375         # emit unconditional jump, then return
15376         (emit-indent *(ebp+8) *Curr-block-depth)
15377         (write-buffered *(ebp+8) "e9/jump ")
15378         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15379         (write-buffered *(ebp+8) %eax)
15380         (write-buffered *(ebp+8) ":")
15381         (write-buffered *(ebp+8) *(ebp+0x14))
15382         (write-buffered *(ebp+8) "/disp32\n")
15383         eb/jump $emit-unconditional-jump-to-depth:end/disp8
15384       }
15385       # curr -= 12
15386       81 5/subop/subtract %esi 0xc/imm32
15387       e9/jump loop/disp32
15388     }
15389     # TODO: error if no label at 'depth' was found
15390 $emit-unconditional-jump-to-depth:end:
15391     # . restore registers
15392     5e/pop-to-esi
15393     5b/pop-to-ebx
15394     5a/pop-to-edx
15395     59/pop-to-ecx
15396     58/pop-to-eax
15397     # . epilogue
15398     89/<- %esp 5/r32/ebp
15399     5d/pop-to-ebp
15400     c3/return
15401 
15402 # emit clean-up code for 'vars' until some block depth
15403 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15404 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
15405     # . prologue
15406     55/push-ebp
15407     89/<- %ebp 4/r32/esp
15408     # . save registers
15409     50/push-eax
15410     51/push-ecx
15411     52/push-edx
15412     53/push-ebx
15413     56/push-esi
15414 #?     (write-buffered Stderr "--- cleanup\n")
15415 #?     (flush Stderr)
15416     # ecx = vars
15417     8b/-> *(ebp+0xc) 1/r32/ecx
15418     # var esi: int = vars->top
15419     8b/-> *ecx 6/r32/esi
15420     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15421     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15422     # var min/ecx: (addr handle var) = vars->data
15423     81 0/subop/add %ecx 8/imm32
15424     # edx = until-block-depth
15425     8b/-> *(ebp+0x10) 2/r32/edx
15426     {
15427 $emit-cleanup-code-until-depth:loop:
15428       # if (curr < min) break
15429       39/compare %esi 1/r32/ecx
15430       0f 82/jump-if-addr< break/disp32
15431       # var v/ebx: (addr var) = lookup(*curr)
15432       (lookup *esi *(esi+4))  # => eax
15433       89/<- %ebx 0/r32/eax
15434 #?       (lookup *ebx *(ebx+4))  # Var-name
15435 #?       (write-buffered Stderr "var ")
15436 #?       (write-buffered Stderr %eax)
15437 #?       (write-buffered Stderr Newline)
15438 #?       (flush Stderr)
15439       # if (v->block-depth < until-block-depth) break
15440       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15441       0f 8c/jump-if-< break/disp32
15442       # if v is in a register
15443       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15444       {
15445         0f 84/jump-if-= break/disp32
15446         {
15447 $emit-cleanup-code-until-depth:check-for-previous-spill:
15448           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
15449           3d/compare-eax-and 0/imm32/false
15450           74/jump-if-= break/disp8
15451 $emit-cleanup-code-until-depth:reclaim-var-in-register:
15452           (emit-indent *(ebp+8) *Curr-block-depth)
15453           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15454           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15455           (write-buffered *(ebp+8) %eax)
15456           (write-buffered *(ebp+8) Newline)
15457         }
15458         eb/jump $emit-cleanup-code-until-depth:continue/disp8
15459       }
15460       # otherwise v is on the stack
15461       {
15462         75/jump-if-!= break/disp8
15463 $emit-cleanup-code-until-depth:var-on-stack:
15464         (size-of %ebx)  # => eax
15465         # don't emit code for labels
15466         3d/compare-eax-and 0/imm32
15467         74/jump-if-= break/disp8
15468 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
15469         (emit-indent *(ebp+8) *Curr-block-depth)
15470         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15471         (write-int32-hex-buffered *(ebp+8) %eax)
15472         (write-buffered *(ebp+8) "/imm32\n")
15473       }
15474 $emit-cleanup-code-until-depth:continue:
15475       # curr -= 12
15476       81 5/subop/subtract %esi 0xc/imm32
15477       e9/jump loop/disp32
15478     }
15479 $emit-cleanup-code-until-depth:end:
15480     # . restore registers
15481     5e/pop-to-esi
15482     5b/pop-to-ebx
15483     5a/pop-to-edx
15484     59/pop-to-ecx
15485     58/pop-to-eax
15486     # . epilogue
15487     89/<- %esp 5/r32/ebp
15488     5d/pop-to-ebp
15489     c3/return
15490 
15491 # emit clean-up code for 'vars' until a given label is encountered
15492 # doesn't actually modify 'vars' so we need traverse manually inside the stack
15493 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
15494     # . prologue
15495     55/push-ebp
15496     89/<- %ebp 4/r32/esp
15497     # . save registers
15498     50/push-eax
15499     51/push-ecx
15500     52/push-edx
15501     53/push-ebx
15502     # ecx = vars
15503     8b/-> *(ebp+0xc) 1/r32/ecx
15504     # var eax: int = vars->top
15505     8b/-> *ecx 0/r32/eax
15506     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15507     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15508     # var min/ecx: (addr handle var) = vars->data
15509     81 0/subop/add %ecx 8/imm32
15510     {
15511 $emit-cleanup-code-until-target:loop:
15512       # if (curr < min) break
15513       39/compare %edx 1/r32/ecx
15514       0f 82/jump-if-addr< break/disp32
15515       # var v/ebx: (handle var) = lookup(*curr)
15516       (lookup *edx *(edx+4))  # => eax
15517       89/<- %ebx 0/r32/eax
15518       # if (v->name == until-block-label) break
15519       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
15520       (string-equal? %eax *(ebp+0x10))  # => eax
15521       3d/compare-eax-and 0/imm32/false
15522       0f 85/jump-if-!= break/disp32
15523       # if v is in a register
15524       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15525       {
15526         0f 84/jump-if-= break/disp32
15527         {
15528 $emit-cleanup-code-until-target:check-for-previous-spill:
15529           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
15530           3d/compare-eax-and 0/imm32/false
15531           74/jump-if-= break/disp8
15532 $emit-cleanup-code-until-target:reclaim-var-in-register:
15533           (emit-indent *(ebp+8) *Curr-block-depth)
15534           (write-buffered *(ebp+8) "8f 0/subop/pop %")
15535           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
15536           (write-buffered *(ebp+8) %eax)
15537           (write-buffered *(ebp+8) Newline)
15538         }
15539         eb/jump $emit-cleanup-code-until-target:continue/disp8
15540       }
15541       # otherwise v is on the stack
15542       {
15543         75/jump-if-!= break/disp8
15544 $emit-cleanup-code-until-target:reclaim-var-on-stack:
15545         (size-of %ebx)  # => eax
15546         # don't emit code for labels
15547         3d/compare-eax-and 0/imm32
15548         74/jump-if-= break/disp8
15549         #
15550         (emit-indent *(ebp+8) *Curr-block-depth)
15551         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
15552         (write-int32-hex-buffered *(ebp+8) %eax)
15553         (write-buffered *(ebp+8) "/imm32\n")
15554       }
15555 $emit-cleanup-code-until-target:continue:
15556       # curr -= 12
15557       81 5/subop/subtract %edx 0xc/imm32
15558       e9/jump loop/disp32
15559     }
15560 $emit-cleanup-code-until-target:end:
15561     # . restore registers
15562     5b/pop-to-ebx
15563     5a/pop-to-edx
15564     59/pop-to-ecx
15565     58/pop-to-eax
15566     # . epilogue
15567     89/<- %esp 5/r32/ebp
15568     5d/pop-to-ebp
15569     c3/return
15570 
15571 # update Curr-local-stack-offset assuming vars until some block depth are popped
15572 # doesn't actually modify 'vars', so we need traverse manually inside the stack
15573 clean-up-stack-offset-state:  # vars: (addr stack live-var), until-block-depth: int
15574     # . prologue
15575     55/push-ebp
15576     89/<- %ebp 4/r32/esp
15577     # . save registers
15578     50/push-eax
15579     51/push-ecx
15580     52/push-edx
15581     53/push-ebx
15582     56/push-esi
15583     # ecx = vars
15584     8b/-> *(ebp+8) 1/r32/ecx
15585     # var esi: int = vars->top
15586     8b/-> *ecx 6/r32/esi
15587     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
15588     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
15589     # var min/ecx: (addr handle var) = vars->data
15590     81 0/subop/add %ecx 8/imm32
15591     # edx = until-block-depth
15592     8b/-> *(ebp+0xc) 2/r32/edx
15593     {
15594 $clean-up-stack-offset-state:loop:
15595       # if (curr < min) break
15596       39/compare %esi 1/r32/ecx
15597       0f 82/jump-if-addr< break/disp32
15598       # var v/ebx: (addr var) = lookup(*curr)
15599       (lookup *esi *(esi+4))  # => eax
15600       89/<- %ebx 0/r32/eax
15601       # if (v->block-depth < until-block-depth) break
15602       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
15603       0f 8c/jump-if-< break/disp32
15604       # if v is in a register
15605       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
15606       {
15607         0f 84/jump-if-= break/disp32
15608         {
15609 $clean-up-stack-offset-state:check-for-previous-spill:
15610           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
15611           3d/compare-eax-and 0/imm32/false
15612           74/jump-if-= break/disp8
15613 $clean-up-stack-offset-state:reclaim-var-in-register:
15614           81 0/subop/add *Curr-local-stack-offset 4/imm32
15615         }
15616         eb/jump $clean-up-stack-offset-state:continue/disp8
15617       }
15618       # otherwise v is on the stack
15619       {
15620         75/jump-if-!= break/disp8
15621 $clean-up-stack-offset-state:var-on-stack:
15622         (size-of %ebx)  # => eax
15623         01/add-to *Curr-local-stack-offset 0/r32/eax
15624       }
15625 $clean-up-stack-offset-state:continue:
15626       # curr -= 12
15627       81 5/subop/subtract %esi 0xc/imm32
15628       e9/jump loop/disp32
15629     }
15630 $clean-up-stack-offset-state:end:
15631     # . restore registers
15632     5e/pop-to-esi
15633     5b/pop-to-ebx
15634     5a/pop-to-edx
15635     59/pop-to-ecx
15636     58/pop-to-eax
15637     # . epilogue
15638     89/<- %esp 5/r32/ebp
15639     5d/pop-to-ebp
15640     c3/return
15641 
15642 # Return true if there isn't a variable in 'vars' with the same block-depth
15643 # and register as 'v'.
15644 # 'v' is guaranteed not to be within 'vars'.
15645 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
15646     # . prologue
15647     55/push-ebp
15648     89/<- %ebp 4/r32/esp
15649     # . save registers
15650     51/push-ecx
15651     52/push-edx
15652     53/push-ebx
15653     56/push-esi
15654     57/push-edi
15655     # ecx = vars
15656     8b/-> *(ebp+0xc) 1/r32/ecx
15657     # var eax: int = vars->top
15658     8b/-> *ecx 0/r32/eax
15659     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
15660     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
15661     # var min/ecx: (addr handle var) = vars->data
15662     8d/copy-address *(ecx+8) 1/r32/ecx
15663     # var depth/ebx: int = v->block-depth
15664     8b/-> *(ebp+8) 3/r32/ebx
15665     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
15666     # var needle/esi: (addr array byte) = v->register
15667     8b/-> *(ebp+8) 6/r32/esi
15668     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15669     89/<- %esi 0/r32/eax
15670     {
15671 $not-yet-spilled-this-block?:loop:
15672       # if (curr < min) break
15673       39/compare %edx 1/r32/ecx
15674       0f 82/jump-if-addr< break/disp32
15675       # var cand/edi: (addr var) = lookup(*curr)
15676       (lookup *edx *(edx+4))  # => eax
15677       89/<- %edi 0/r32/eax
15678       # if (cand->block-depth < depth) break
15679       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
15680       0f 8c/jump-if-< break/disp32
15681       # var cand-reg/edi: (array array byte) = cand->reg
15682       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
15683       89/<- %edi 0/r32/eax
15684       # if (cand-reg == null) continue
15685       {
15686 $not-yet-spilled-this-block?:check-reg:
15687         81 7/subop/compare %edi 0/imm32
15688         0f 84/jump-if-= break/disp32
15689         # if (cand-reg == needle) return true
15690         (string-equal? %esi %edi)  # => eax
15691         3d/compare-eax-and 0/imm32/false
15692         74/jump-if-= break/disp8
15693 $not-yet-spilled-this-block?:return-false:
15694         b8/copy-to-eax 0/imm32/false
15695         eb/jump $not-yet-spilled-this-block?:end/disp8
15696       }
15697 $not-yet-spilled-this-block?:continue:
15698       # curr -= 12
15699       81 5/subop/subtract %edx 0xc/imm32
15700       e9/jump loop/disp32
15701     }
15702 $not-yet-spilled-this-block?:return-true:
15703     # return true
15704     b8/copy-to-eax 1/imm32/true
15705 $not-yet-spilled-this-block?:end:
15706     # . restore registers
15707     5f/pop-to-edi
15708     5e/pop-to-esi
15709     5b/pop-to-ebx
15710     5a/pop-to-edx
15711     59/pop-to-ecx
15712     # . epilogue
15713     89/<- %esp 5/r32/ebp
15714     5d/pop-to-ebp
15715     c3/return
15716 
15717 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
15718 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
15719     # . prologue
15720     55/push-ebp
15721     89/<- %ebp 4/r32/esp
15722     # eax = v
15723     8b/-> *(ebp+8) 0/r32/eax
15724     # var reg/eax: (addr array byte) = lookup(v->register)
15725     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15726     # var target/eax: (addr var) = find-register(fn-outputs, reg)
15727     (find-register *(ebp+0x10) %eax)  # => eax
15728     # if (target == 0) return true
15729     {
15730       3d/compare-eax-and 0/imm32
15731       75/jump-if-!= break/disp8
15732       b8/copy-to-eax 1/imm32/true
15733       eb/jump $will-not-write-some-register?:end/disp8
15734     }
15735     # return !assigns-in-stmts?(stmts, target)
15736     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
15737     3d/compare-eax-and 0/imm32/false
15738     # assume: true = 1, so no need to mask with 0x000000ff
15739     0f 94/set-if-= %al
15740 $will-not-write-some-register?:end:
15741     # . epilogue
15742     89/<- %esp 5/r32/ebp
15743     5d/pop-to-ebp
15744     c3/return
15745 
15746 # return fn output with matching register
15747 # always returns false if 'reg' is null
15748 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
15749     # . prologue
15750     55/push-ebp
15751     89/<- %ebp 4/r32/esp
15752     # . save registers
15753     51/push-ecx
15754     # var curr/ecx: (addr list var) = lookup(fn->outputs)
15755     8b/-> *(ebp+8) 1/r32/ecx
15756     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
15757     89/<- %ecx 0/r32/eax
15758     {
15759 $find-register:loop:
15760       # if (curr == 0) break
15761       81 7/subop/compare %ecx 0/imm32
15762       74/jump-if-= break/disp8
15763       # eax = curr->value->register
15764       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15765       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15766       # if (eax == reg) return curr->value
15767 $find-register:compare:
15768       (string-equal? *(ebp+0xc) %eax)  # => eax
15769       {
15770         3d/compare-eax-and 0/imm32/false
15771         74/jump-if-= break/disp8
15772 $find-register:found:
15773         (lookup *ecx *(ecx+4))  # List-value List-value => eax
15774         eb/jump $find-register:end/disp8
15775       }
15776       # curr = lookup(curr->next)
15777       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15778       89/<- %ecx 0/r32/eax
15779       #
15780       eb/jump loop/disp8
15781     }
15782 $find-register:end:
15783     # . restore registers
15784     59/pop-to-ecx
15785     # . epilogue
15786     89/<- %esp 5/r32/ebp
15787     5d/pop-to-ebp
15788     c3/return
15789 
15790 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
15791     # . prologue
15792     55/push-ebp
15793     89/<- %ebp 4/r32/esp
15794     # . save registers
15795     51/push-ecx
15796     # var curr/ecx: (addr list stmt) = stmts
15797     8b/-> *(ebp+8) 1/r32/ecx
15798     {
15799       # if (curr == 0) break
15800       81 7/subop/compare %ecx 0/imm32
15801       74/jump-if-= break/disp8
15802       # if assigns-in-stmt?(curr->value, v) return true
15803       (lookup *ecx *(ecx+4))  # List-value List-value => eax
15804       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
15805       3d/compare-eax-and 0/imm32/false
15806       75/jump-if-!= break/disp8
15807       # curr = lookup(curr->next)
15808       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
15809       89/<- %ecx 0/r32/eax
15810       #
15811       eb/jump loop/disp8
15812     }
15813 $assigns-in-stmts?:end:
15814     # . restore registers
15815     59/pop-to-ecx
15816     # . epilogue
15817     89/<- %esp 5/r32/ebp
15818     5d/pop-to-ebp
15819     c3/return
15820 
15821 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
15822     # . prologue
15823     55/push-ebp
15824     89/<- %ebp 4/r32/esp
15825     # . save registers
15826     51/push-ecx
15827     # ecx = stmt
15828     8b/-> *(ebp+8) 1/r32/ecx
15829     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
15830     {
15831       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
15832       75/jump-if-!= break/disp8
15833       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15834       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
15835       eb/jump $assigns-in-stmt?:end/disp8
15836     }
15837     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
15838     {
15839       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
15840       75/jump-if-!= break/disp8
15841       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
15842       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
15843       eb/jump $assigns-in-stmt?:end/disp8
15844     }
15845     # otherwise return false
15846     b8/copy 0/imm32/false
15847 $assigns-in-stmt?:end:
15848     # . restore registers
15849     59/pop-to-ecx
15850     # . epilogue
15851     89/<- %esp 5/r32/ebp
15852     5d/pop-to-ebp
15853     c3/return
15854 
15855 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
15856     # . prologue
15857     55/push-ebp
15858     89/<- %ebp 4/r32/esp
15859     # . save registers
15860     51/push-ecx
15861     # var curr/ecx: (addr stmt-var) = stmt-var
15862     8b/-> *(ebp+8) 1/r32/ecx
15863     {
15864       # if (curr == 0) break
15865       81 7/subop/compare %ecx 0/imm32
15866       74/jump-if-= break/disp8
15867       # eax = lookup(curr->value)
15868       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15869       # if (eax == v  &&  curr->is-deref? == false) return true
15870       {
15871         39/compare *(ebp+0xc) 0/r32/eax
15872         75/jump-if-!= break/disp8
15873         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15874         75/jump-if-!= break/disp8
15875         b8/copy-to-eax 1/imm32/true
15876         eb/jump $assigns-in-stmt-vars?:end/disp8
15877       }
15878       # curr = lookup(curr->next)
15879       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
15880       89/<- %ecx 0/r32/eax
15881       #
15882       eb/jump loop/disp8
15883     }
15884 $assigns-in-stmt-vars?:end:
15885     # . restore registers
15886     59/pop-to-ecx
15887     # . epilogue
15888     89/<- %esp 5/r32/ebp
15889     5d/pop-to-ebp
15890     c3/return
15891 
15892 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
15893 # v is guaranteed to be within vars
15894 # 'start' is provided as an optimization, a pointer within vars
15895 # *start == v
15896 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
15897     # . prologue
15898     55/push-ebp
15899     89/<- %ebp 4/r32/esp
15900     # . save registers
15901     51/push-ecx
15902     52/push-edx
15903     53/push-ebx
15904     56/push-esi
15905     57/push-edi
15906     # ecx = v
15907     8b/-> *(ebp+8) 1/r32/ecx
15908     # var reg/edx: (addr array byte) = lookup(v->register)
15909     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
15910     89/<- %edx 0/r32/eax
15911     # var depth/ebx: int = v->block-depth
15912     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
15913     # var min/ecx: (addr handle var) = vars->data
15914     8b/-> *(ebp+0xc) 1/r32/ecx
15915     81 0/subop/add %ecx 8/imm32
15916     # TODO: check that start >= min and start < &vars->data[top]
15917     # TODO: check that *start == v
15918     # var curr/esi: (addr handle var) = start
15919     8b/-> *(ebp+0x10) 6/r32/esi
15920     # curr -= 8
15921     81 5/subop/subtract %esi 8/imm32
15922     {
15923 $same-register-spilled-before?:loop:
15924       # if (curr < min) break
15925       39/compare %esi 1/r32/ecx
15926       0f 82/jump-if-addr< break/disp32
15927       # var x/eax: (addr var) = lookup(*curr)
15928       (lookup *esi *(esi+4))  # => eax
15929       # if (x->block-depth < depth) break
15930       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
15931       0f 8c/jump-if-< break/disp32
15932       # if (x->register == 0) continue
15933       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
15934       74/jump-if-= $same-register-spilled-before?:continue/disp8
15935       # if (x->register == reg) return true
15936       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15937       (string-equal? %eax %edx)  # => eax
15938       3d/compare-eax-and 0/imm32/false
15939       b8/copy-to-eax 1/imm32/true
15940       75/jump-if-!= $same-register-spilled-before?:end/disp8
15941 $same-register-spilled-before?:continue:
15942       # curr -= 8
15943       81 5/subop/subtract %esi 8/imm32
15944       e9/jump loop/disp32
15945     }
15946 $same-register-spilled-before?:false:
15947     b8/copy-to-eax 0/imm32/false
15948 $same-register-spilled-before?:end:
15949     # . restore registers
15950     5f/pop-to-edi
15951     5e/pop-to-esi
15952     5b/pop-to-ebx
15953     5a/pop-to-edx
15954     59/pop-to-ecx
15955     # . epilogue
15956     89/<- %esp 5/r32/ebp
15957     5d/pop-to-ebp
15958     c3/return
15959 
15960 # Clean up global state for 'vars' until some block depth (inclusive).
15961 #
15962 # This would be a simple series of pops, if it wasn't for fn outputs, which
15963 # can occur anywhere in the stack.
15964 # So we have to _compact_ the entire array underlying the stack.
15965 #
15966 # We want to allow a fn output register to be written to by locals before the
15967 # output is set.
15968 # So fn outputs can't just be pushed at the start of the function.
15969 #
15970 # We want to allow other locals to shadow a fn output register after the
15971 # output is set.
15972 # So the output can't just always override anything in the stack. Sequence matters.
15973 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
15974     # pseudocode:
15975     #   to = vars->top  (which points outside the stack)
15976     #   while true
15977     #     if to <= 0
15978     #       break
15979     #     var v = vars->data[to-1]
15980     #     if v.depth < until and !in-function-outputs?(fn, v)
15981     #       break
15982     #     --to
15983     #   from = to
15984     #   while true
15985     #     if from >= vars->top
15986     #       break
15987     #     assert(from >= to)
15988     #     v = vars->data[from]
15989     #     if in-function-outputs?(fn, v)
15990     #       if from > to
15991     #         vars->data[to] = vars->data[from]
15992     #       ++to
15993     #     ++from
15994     #   vars->top = to
15995     #
15996     # . prologue
15997     55/push-ebp
15998     89/<- %ebp 4/r32/esp
15999     # . save registers
16000     50/push-eax
16001     52/push-edx
16002     53/push-ebx
16003     56/push-esi
16004     57/push-edi
16005     # ebx = vars
16006     8b/-> *(ebp+8) 3/r32/ebx
16007     # edx = until-block-depth
16008     8b/-> *(ebp+0xc) 2/r32/edx
16009 $clean-up-blocks:phase1:
16010     # var to/edi: int = vars->top
16011     8b/-> *ebx 7/r32/edi
16012     {
16013 $clean-up-blocks:loop1:
16014       # if (to <= 0) break
16015       81 7/subop/compare %edi 0/imm32
16016       7e/jump-if-<= break/disp8
16017       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
16018       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
16019       (lookup *eax *(eax+4))  # => eax
16020       # if (v->block-depth >= until-block-depth) continue
16021       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
16022       {
16023         7d/jump-if->= break/disp8
16024         # if (!in-function-outputs?(fn, v)) break
16025         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
16026         3d/compare-eax-and 0/imm32/false
16027         74/jump-if-= $clean-up-blocks:phase2/disp8
16028       }
16029 $clean-up-blocks:loop1-continue:
16030       # --to
16031       81 5/subop/subtract %edi 0xc/imm32
16032       #
16033       eb/jump loop/disp8
16034     }
16035 $clean-up-blocks:phase2:
16036     # var from/esi: int = to
16037     89/<- %esi 7/r32/edi
16038     {
16039 $clean-up-blocks:loop2:
16040       # if (from >= vars->top) break
16041       3b/compare 6/r32/esi *ebx
16042       7d/jump-if->= break/disp8
16043       # var v/eax: (addr var) = lookup(vars->data[from]->var)
16044       8d/copy-address *(ebx+esi+8) 0/r32/eax
16045       (lookup *eax *(eax+4))  # => eax
16046       # if !in-function-outputs?(fn, v) continue
16047       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
16048       3d/compare-eax-and 0/imm32/false
16049       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
16050       # invariant: from >= to
16051       # if (from > to) vars->data[to] = vars->data[from]
16052       {
16053         39/compare %esi 7/r32/edi
16054         7e/jump-if-<= break/disp8
16055         56/push-esi
16056         57/push-edi
16057         # . var from/esi: (addr byte) = &vars->data[from]
16058         8d/copy-address *(ebx+esi+8) 6/r32/esi
16059         # . var to/edi: (addr byte) = &vars->data[to]
16060         8d/copy-address *(ebx+edi+8) 7/r32/edi
16061         # .
16062         8b/-> *esi 0/r32/eax
16063         89/<- *edi 0/r32/eax
16064         8b/-> *(esi+4) 0/r32/eax
16065         89/<- *(edi+4) 0/r32/eax
16066         8b/-> *(esi+8) 0/r32/eax
16067         89/<- *(edi+8) 0/r32/eax
16068         5f/pop-to-edi
16069         5e/pop-to-esi
16070       }
16071       # ++to
16072       81 0/subop/add %edi 0xc/imm32
16073 $clean-up-blocks:loop2-continue:
16074       # ++from
16075       81 0/subop/add %esi 0xc/imm32
16076       #
16077       eb/jump loop/disp8
16078     }
16079     89/<- *ebx 7/r32/edi
16080 $clean-up-blocks:end:
16081     # . restore registers
16082     5f/pop-to-edi
16083     5e/pop-to-esi
16084     5b/pop-to-ebx
16085     5a/pop-to-edx
16086     58/pop-to-eax
16087     # . epilogue
16088     89/<- %esp 5/r32/ebp
16089     5d/pop-to-ebp
16090     c3/return
16091 
16092 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
16093     # . prologue
16094     55/push-ebp
16095     89/<- %ebp 4/r32/esp
16096     # . save registers
16097     51/push-ecx
16098     # var curr/ecx: (addr list var) = lookup(fn->outputs)
16099     8b/-> *(ebp+8) 1/r32/ecx
16100     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
16101     89/<- %ecx 0/r32/eax
16102     # while curr != null
16103     {
16104       81 7/subop/compare %ecx 0/imm32
16105       74/jump-if-= break/disp8
16106       # var v/eax: (addr var) = lookup(curr->value)
16107       (lookup *ecx *(ecx+4))  # List-value List-value => eax
16108       # if (v == target) return true
16109       39/compare *(ebp+0xc) 0/r32/eax
16110       b8/copy-to-eax 1/imm32/true
16111       74/jump-if-= $in-function-outputs?:end/disp8
16112       # curr = curr->next
16113       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
16114       89/<- %ecx 0/r32/eax
16115       #
16116       eb/jump loop/disp8
16117     }
16118     b8/copy-to-eax 0/imm32
16119 $in-function-outputs?:end:
16120     # . restore registers
16121     59/pop-to-ecx
16122     # . epilogue
16123     89/<- %esp 5/r32/ebp
16124     5d/pop-to-ebp
16125     c3/return
16126 
16127 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
16128     # . prologue
16129     55/push-ebp
16130     89/<- %ebp 4/r32/esp
16131     # . save registers
16132     50/push-eax
16133     51/push-ecx
16134     52/push-edx
16135     # eax = stmt
16136     8b/-> *(ebp+0xc) 0/r32/eax
16137     # var v/ecx: (addr var)
16138     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
16139     89/<- %ecx 0/r32/eax
16140     # v->block-depth = *Curr-block-depth
16141     8b/-> *Curr-block-depth 0/r32/eax
16142     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
16143     # var n/edx: int = size-of(stmt->var)
16144     (size-of %ecx)  # => eax
16145     89/<- %edx 0/r32/eax
16146     # *Curr-local-stack-offset -= n
16147     29/subtract-from *Curr-local-stack-offset 2/r32/edx
16148     # v->offset = *Curr-local-stack-offset
16149     8b/-> *Curr-local-stack-offset 0/r32/eax
16150     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
16151     # if v is an array, do something special to initialize it
16152     {
16153       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
16154       (is-mu-array? %eax)  # => eax
16155       3d/compare-eax-and 0/imm32/false
16156       0f 84/jump-if-= break/disp32
16157       # var array-size-without-size/edx: int = n-4
16158       81 5/subop/subtract %edx 4/imm32
16159       #
16160       (emit-array-data-initialization *(ebp+8) %edx)
16161       e9/jump $emit-subx-var-def:end/disp32
16162     }
16163     # another special-case for initializing streams
16164     # a stream is an array with 2 extra pointers
16165     {
16166       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
16167       (is-mu-stream? %eax)  # => eax
16168       3d/compare-eax-and 0/imm32/false
16169       0f 84/jump-if-= break/disp32
16170       # var array-size-without-size/edx: int = n-12
16171       81 5/subop/subtract %edx 0xc/imm32
16172       (emit-array-data-initialization *(ebp+8) %edx)
16173       # emit read and write pointers
16174       (emit-indent *(ebp+8) *Curr-block-depth)
16175       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16176       (emit-indent *(ebp+8) *Curr-block-depth)
16177       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16178       #
16179       eb/jump $emit-subx-var-def:end/disp8
16180     }
16181     # while n > 0
16182     {
16183       81 7/subop/compare %edx 0/imm32
16184       7e/jump-if-<= break/disp8
16185       (emit-indent *(ebp+8) *Curr-block-depth)
16186       (write-buffered *(ebp+8) "68/push 0/imm32\n")
16187       # n -= 4
16188       81 5/subop/subtract %edx 4/imm32
16189       #
16190       eb/jump loop/disp8
16191     }
16192 $emit-subx-var-def:end:
16193     # . restore registers
16194     5a/pop-to-edx
16195     59/pop-to-ecx
16196     58/pop-to-eax
16197     # . epilogue
16198     89/<- %esp 5/r32/ebp
16199     5d/pop-to-ebp
16200     c3/return
16201 
16202 emit-array-data-initialization:  # out: (addr buffered-file), n: int
16203     # . prologue
16204     55/push-ebp
16205     89/<- %ebp 4/r32/esp
16206     #
16207     (emit-indent *(ebp+8) *Curr-block-depth)
16208     (write-buffered *(ebp+8) "(push-n-zero-bytes ")
16209     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
16210     (write-buffered *(ebp+8) ")\n")
16211     (emit-indent *(ebp+8) *Curr-block-depth)
16212     (write-buffered *(ebp+8) "68/push ")
16213     (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
16214     (write-buffered *(ebp+8) "/imm32\n")
16215 $emit-array-data-initialization:end:
16216     # . epilogue
16217     89/<- %esp 5/r32/ebp
16218     5d/pop-to-ebp
16219     c3/return
16220 
16221 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
16222     # . prologue
16223     55/push-ebp
16224     89/<- %ebp 4/r32/esp
16225     # . save registers
16226     50/push-eax
16227     51/push-ecx
16228     # - some special-case primitives that don't actually use the 'primitives' data structure
16229     # var op/ecx: (addr array byte) = lookup(stmt->operation)
16230     8b/-> *(ebp+0xc) 1/r32/ecx
16231     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
16232     89/<- %ecx 0/r32/eax
16233     # array size
16234     {
16235       # if (!string-equal?(stmt->operation, "length")) break
16236       (string-equal? %ecx "length")  # => eax
16237       3d/compare-eax-and 0/imm32
16238       0f 84/jump-if-= break/disp32
16239       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16240       e9/jump $emit-subx-stmt:end/disp32
16241     }
16242     # index into array
16243     {
16244       # if (!string-equal?(stmt->operation, "index")) break
16245       (string-equal? %ecx "index")  # => eax
16246       3d/compare-eax-and 0/imm32
16247       0f 84/jump-if-= break/disp32
16248       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16249       e9/jump $emit-subx-stmt:end/disp32
16250     }
16251     # compute-offset for index into array
16252     {
16253       # if (!string-equal?(stmt->operation, "compute-offset")) break
16254       (string-equal? %ecx "compute-offset")  # => eax
16255       3d/compare-eax-and 0/imm32
16256       0f 84/jump-if-= break/disp32
16257       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16258       e9/jump $emit-subx-stmt:end/disp32
16259     }
16260     # get field from record
16261     {
16262       # if (!string-equal?(stmt->operation, "get")) break
16263       (string-equal? %ecx "get")  # => eax
16264       3d/compare-eax-and 0/imm32
16265       0f 84/jump-if-= break/disp32
16266       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
16267       e9/jump $emit-subx-stmt:end/disp32
16268     }
16269     # allocate scalar
16270     {
16271       # if (!string-equal?(stmt->operation, "allocate")) break
16272       (string-equal? %ecx "allocate")  # => eax
16273       3d/compare-eax-and 0/imm32
16274       0f 84/jump-if-= break/disp32
16275       (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16276       e9/jump $emit-subx-stmt:end/disp32
16277     }
16278     # copy-object
16279     {
16280       # if (!string-equal?(stmt->operation, "copy-object")) break
16281       (string-equal? %ecx "copy-object")  # => eax
16282       3d/compare-eax-and 0/imm32
16283       0f 84/jump-if-= break/disp32
16284       (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16285       e9/jump $emit-subx-stmt:end/disp32
16286     }
16287     # allocate array
16288     {
16289       # if (!string-equal?(stmt->operation, "populate")) break
16290       (string-equal? %ecx "populate")  # => eax
16291       3d/compare-eax-and 0/imm32
16292       0f 84/jump-if-= break/disp32
16293       (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16294       e9/jump $emit-subx-stmt:end/disp32
16295     }
16296     # allocate stream
16297     {
16298       # if (!string-equal?(stmt->operation, "populate-stream")) break
16299       (string-equal? %ecx "populate-stream")  # => eax
16300       3d/compare-eax-and 0/imm32
16301       0f 84/jump-if-= break/disp32
16302       (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16303       e9/jump $emit-subx-stmt:end/disp32
16304     }
16305     # read from stream
16306     {
16307       # if (!string-equal?(stmt->operation, "read-from-stream")) break
16308       (string-equal? %ecx "read-from-stream")  # => eax
16309       3d/compare-eax-and 0/imm32
16310       0f 84/jump-if-= break/disp32
16311       (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16312       e9/jump $emit-subx-stmt:end/disp32
16313     }
16314     # write to stream
16315     {
16316       # if (!string-equal?(stmt->operation, "write-to-stream")) break
16317       (string-equal? %ecx "write-to-stream")  # => eax
16318       3d/compare-eax-and 0/imm32
16319       0f 84/jump-if-= break/disp32
16320       (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
16321       e9/jump $emit-subx-stmt:end/disp32
16322     }
16323     # - if stmt matches a primitive, emit it
16324     {
16325 $emit-subx-stmt:check-for-primitive:
16326       # var curr/eax: (addr primitive)
16327       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
16328       3d/compare-eax-and 0/imm32
16329       74/jump-if-= break/disp8
16330 $emit-subx-stmt:primitive:
16331       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
16332       e9/jump $emit-subx-stmt:end/disp32
16333     }
16334     # - otherwise emit a call
16335     # TODO: type-checking
16336 $emit-subx-stmt:call:
16337     (emit-call *(ebp+8) *(ebp+0xc))
16338 $emit-subx-stmt:end:
16339     # . restore registers
16340     59/pop-to-ecx
16341     58/pop-to-eax
16342     # . epilogue
16343     89/<- %esp 5/r32/ebp
16344     5d/pop-to-ebp
16345     c3/return
16346 
16347 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16348     # . prologue
16349     55/push-ebp
16350     89/<- %ebp 4/r32/esp
16351     # . save registers
16352     50/push-eax
16353     51/push-ecx
16354     52/push-edx
16355     53/push-ebx
16356     56/push-esi
16357     # esi = stmt
16358     8b/-> *(ebp+0xc) 6/r32/esi
16359     # var base/ebx: (addr var) = stmt->inouts[0]->value
16360     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16361     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16362     89/<- %ebx 0/r32/eax
16363     # var elemsize/ecx: int = array-element-size(base)
16364     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16365     89/<- %ecx 0/r32/eax
16366     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
16367     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16368     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16369     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16370     89/<- %edx 0/r32/eax
16371     # if elemsize == 1
16372     {
16373       81 7/subop/compare %ecx 1/imm32
16374       75/jump-if-!= break/disp8
16375 $translate-mu-length-stmt:size-1:
16376       (emit-save-size-to *(ebp+8) %ebx %edx)
16377       e9/jump $translate-mu-length-stmt:end/disp32
16378     }
16379     # if elemsize is a power of 2 less than 256
16380     {
16381       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16382       3d/compare-eax-and 0/imm32/false
16383       74/jump-if-= break/disp8
16384       81 7/subop/compare %ecx 0xff/imm32
16385       7f/jump-if-> break/disp8
16386 $translate-mu-length-stmt:size-power-of-2:
16387       (emit-save-size-to *(ebp+8) %ebx %edx)
16388       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
16389       e9/jump $translate-mu-length-stmt:end/disp32
16390     }
16391     # otherwise, the complex case
16392     # . emit register spills
16393     {
16394 $translate-mu-length-stmt:complex:
16395       (string-equal? %edx "eax")  # => eax
16396       3d/compare-eax-and 0/imm32/false
16397       75/break-if-!= break/disp8
16398       (emit-indent *(ebp+8) *Curr-block-depth)
16399       (write-buffered *(ebp+8) "50/push-eax\n")
16400     }
16401     {
16402       (string-equal? %edx "ecx")  # => eax
16403       3d/compare-eax-and 0/imm32/false
16404       75/break-if-!= break/disp8
16405       (emit-indent *(ebp+8) *Curr-block-depth)
16406       (write-buffered *(ebp+8) "51/push-ecx\n")
16407     }
16408     {
16409       (string-equal? %edx "edx")  # => eax
16410       3d/compare-eax-and 0/imm32/false
16411       75/break-if-!= break/disp8
16412       (emit-indent *(ebp+8) *Curr-block-depth)
16413       (write-buffered *(ebp+8) "52/push-edx\n")
16414     }
16415     # .
16416     (emit-save-size-to *(ebp+8) %ebx "eax")
16417     (emit-indent *(ebp+8) *Curr-block-depth)
16418     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
16419     (emit-indent *(ebp+8) *Curr-block-depth)
16420     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
16421     (write-int32-hex-buffered *(ebp+8) %ecx)
16422     (write-buffered *(ebp+8) "/imm32\n")
16423     (emit-indent *(ebp+8) *Curr-block-depth)
16424     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
16425     {
16426       (string-equal? %edx "eax")  # => eax
16427       3d/compare-eax-and 0/imm32/false
16428       75/break-if-!= break/disp8
16429       (emit-indent *(ebp+8) *Curr-block-depth)
16430       (write-buffered *(ebp+8) "89/<- %")
16431       (write-buffered *(ebp+8) %edx)
16432       (write-buffered *(ebp+8) " 0/r32/eax\n")
16433     }
16434     # . emit register restores
16435     {
16436       (string-equal? %edx "edx")  # => eax
16437       3d/compare-eax-and 0/imm32/false
16438       75/break-if-!= break/disp8
16439       (emit-indent *(ebp+8) *Curr-block-depth)
16440       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
16441     }
16442     {
16443       (string-equal? %edx "ecx")  # => eax
16444       3d/compare-eax-and 0/imm32/false
16445       75/break-if-!= break/disp8
16446       (emit-indent *(ebp+8) *Curr-block-depth)
16447       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
16448     }
16449     {
16450       (string-equal? %edx "eax")  # => eax
16451       3d/compare-eax-and 0/imm32/false
16452       75/break-if-!= break/disp8
16453       (emit-indent *(ebp+8) *Curr-block-depth)
16454       (write-buffered *(ebp+8) "58/pop-to-eax\n")
16455     }
16456 $translate-mu-length-stmt:end:
16457     # . restore registers
16458     5e/pop-to-esi
16459     5b/pop-to-ebx
16460     5a/pop-to-edx
16461     59/pop-to-ecx
16462     58/pop-to-eax
16463     # . epilogue
16464     89/<- %esp 5/r32/ebp
16465     5d/pop-to-ebp
16466     c3/return
16467 
16468 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
16469     # . prologue
16470     55/push-ebp
16471     89/<- %ebp 4/r32/esp
16472     #
16473     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
16474     (size-of-type-id-as-array-element %eax)  # => eax
16475 $array-element-size:end:
16476     # . epilogue
16477     89/<- %esp 5/r32/ebp
16478     5d/pop-to-ebp
16479     c3/return
16480 
16481 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
16482     # precondition: n is positive
16483     # . prologue
16484     55/push-ebp
16485     89/<- %ebp 4/r32/esp
16486     #
16487     8b/-> *(ebp+8) 0/r32/eax
16488     # var t/eax: (addr type-tree)
16489     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
16490     # if t == 0 abort
16491     3d/compare-eax-with 0/imm32
16492     0f 84/jump-if-== $array-element-type-id:error0/disp32
16493     # if t->is-atom? abort
16494     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16495     0f 85/jump-if-!= $array-element-type-id:error1/disp32
16496     # if (t->left == addr) t = t->right
16497     {
16498       50/push-eax
16499       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16500       (is-simple-mu-type? %eax 2)  # addr => eax
16501       3d/compare-eax-with 0/imm32/false
16502       58/pop-to-eax
16503       74/jump-if-= break/disp8
16504 $array-element-type-id:skip-addr:
16505       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16506     }
16507     # if t == 0 abort
16508     3d/compare-eax-with 0/imm32
16509     0f 84/jump-if-= $array-element-type-id:error2/disp32
16510     # if t->is-atom? abort
16511     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16512     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16513     # if t->left != array abort
16514     {
16515       50/push-eax
16516       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16517       (is-simple-mu-type? %eax 3)  # array => eax
16518       3d/compare-eax-with 0/imm32/false
16519       58/pop-to-eax
16520 $array-element-type-id:no-array:
16521       0f 84/jump-if-= $array-element-type-id:error2/disp32
16522     }
16523 $array-element-type-id:skip-array:
16524     # t = t->right
16525     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
16526     # if t == 0 abort
16527     3d/compare-eax-with 0/imm32
16528     0f 84/jump-if-= $array-element-type-id:error2/disp32
16529     # if t->is-atom? abort
16530     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16531     0f 85/jump-if-!= $array-element-type-id:error2/disp32
16532     # return t->left->value
16533     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16534     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
16535 $array-element-type-id:end:
16536     # . epilogue
16537     89/<- %esp 5/r32/ebp
16538     5d/pop-to-ebp
16539     c3/return
16540 
16541 $array-element-type-id:error0:
16542     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16543     50/push-eax
16544     8b/-> *(ebp+8) 0/r32/eax
16545     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16546     (write-buffered *(ebp+0xc) %eax)
16547     58/pop-to-eax
16548     (write-buffered *(ebp+0xc) "' has no type\n")
16549     (flush *(ebp+0xc))
16550     (stop *(ebp+0x10) 1)
16551     # never gets here
16552 
16553 $array-element-type-id:error1:
16554     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16555     50/push-eax
16556     8b/-> *(ebp+8) 0/r32/eax
16557     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16558     (write-buffered *(ebp+0xc) %eax)
16559     58/pop-to-eax
16560     (write-buffered *(ebp+0xc) "' has atomic type ")
16561     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
16562     (write-buffered *(ebp+0xc) Newline)
16563     (flush *(ebp+0xc))
16564     (stop *(ebp+0x10) 1)
16565     # never gets here
16566 
16567 $array-element-type-id:error2:
16568     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
16569     50/push-eax
16570     8b/-> *(ebp+8) 0/r32/eax
16571     (lookup *eax *(eax+4))  # Var-name Var-name => eax
16572     (write-buffered *(ebp+0xc) %eax)
16573     58/pop-to-eax
16574     (write-buffered *(ebp+0xc) "' has non-array type\n")
16575     (flush *(ebp+0xc))
16576     (stop *(ebp+0x10) 1)
16577     # never gets here
16578 
16579 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
16580     # . prologue
16581     55/push-ebp
16582     89/<- %ebp 4/r32/esp
16583     # eax = t
16584     8b/-> *(ebp+8) 0/r32/eax
16585     # if t is 'byte', size is 1
16586     3d/compare-eax-and 8/imm32/byte
16587     {
16588       75/jump-if-!= break/disp8
16589       b8/copy-to-eax 1/imm32
16590       eb/jump $size-of-type-id-as-array-element:end/disp8
16591     }
16592     # otherwise proceed as usual
16593     (size-of-type-id %eax)  # => eax
16594 $size-of-type-id-as-array-element:end:
16595     # . epilogue
16596     89/<- %esp 5/r32/ebp
16597     5d/pop-to-ebp
16598     c3/return
16599 
16600 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
16601     # . prologue
16602     55/push-ebp
16603     89/<- %ebp 4/r32/esp
16604     # . save registers
16605     50/push-eax
16606     53/push-ebx
16607     # ebx = base
16608     8b/-> *(ebp+0xc) 3/r32/ebx
16609     (emit-indent *(ebp+8) *Curr-block-depth)
16610     (write-buffered *(ebp+8) "8b/-> *")
16611     # if base is an (addr array ...) in a register
16612     {
16613       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
16614       74/jump-if-= break/disp8
16615 $emit-save-size-to:emit-base-from-register:
16616       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16617       (write-buffered *(ebp+8) %eax)
16618       eb/jump $emit-save-size-to:emit-output/disp8
16619     }
16620     # otherwise if base is an (array ...) on the stack
16621     {
16622       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
16623       74/jump-if-= break/disp8
16624 $emit-save-size-to:emit-base-from-stack:
16625       (write-buffered *(ebp+8) "(ebp+")
16626       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
16627       (write-buffered *(ebp+8) ")")
16628     }
16629 $emit-save-size-to:emit-output:
16630     (write-buffered *(ebp+8) " ")
16631     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
16632     (write-int32-hex-buffered *(ebp+8) *eax)
16633     (write-buffered *(ebp+8) "/r32\n")
16634 $emit-save-size-to:end:
16635     # . restore registers
16636     5b/pop-to-ebx
16637     58/pop-to-eax
16638     # . epilogue
16639     89/<- %esp 5/r32/ebp
16640     5d/pop-to-ebp
16641     c3/return
16642 
16643 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
16644     # . prologue
16645     55/push-ebp
16646     89/<- %ebp 4/r32/esp
16647     # . save registers
16648     50/push-eax
16649     #
16650     (emit-indent *(ebp+8) *Curr-block-depth)
16651     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
16652     (write-buffered *(ebp+8) *(ebp+0xc))
16653     (write-buffered *(ebp+8) Space)
16654     (num-shift-rights *(ebp+0x10))  # => eax
16655     (write-int32-hex-buffered *(ebp+8) %eax)
16656     (write-buffered *(ebp+8) "/imm8\n")
16657 $emit-divide-by-shift-right:end:
16658     # . restore registers
16659     58/pop-to-eax
16660     # . epilogue
16661     89/<- %esp 5/r32/ebp
16662     5d/pop-to-ebp
16663     c3/return
16664 
16665 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16666     # . prologue
16667     55/push-ebp
16668     89/<- %ebp 4/r32/esp
16669     # . save registers
16670     51/push-ecx
16671     # ecx = stmt
16672     8b/-> *(ebp+0xc) 1/r32/ecx
16673     # var base/ecx: (addr var) = stmt->inouts[0]
16674     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16675     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16676     89/<- %ecx 0/r32/eax
16677     # if (var->register) do one thing
16678     {
16679       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
16680       74/jump-if-= break/disp8
16681       # TODO: ensure there's no dereference
16682       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16683       eb/jump $translate-mu-index-stmt:end/disp8
16684     }
16685     # if (var->offset) do a different thing
16686     {
16687       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
16688       74/jump-if-= break/disp8
16689       # TODO: ensure there's no dereference
16690       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
16691       eb/jump $translate-mu-index-stmt:end/disp8
16692     }
16693 $translate-mu-index-stmt:end:
16694     # . restore registers
16695     59/pop-to-ecx
16696     # . epilogue
16697     89/<- %esp 5/r32/ebp
16698     5d/pop-to-ebp
16699     c3/return
16700 
16701 $translate-mu-index-stmt-with-array:error1:
16702     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
16703     (flush *(ebp+0x10))
16704     (stop *(ebp+0x14) 1)
16705     # never gets here
16706 
16707 $translate-mu-index-stmt-with-array:error2:
16708     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
16709     (flush *(ebp+0x10))
16710     (stop *(ebp+0x14) 1)
16711     # never gets here
16712 
16713 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16714     # . prologue
16715     55/push-ebp
16716     89/<- %ebp 4/r32/esp
16717     # . save registers
16718     50/push-eax
16719     51/push-ecx
16720     52/push-edx
16721     53/push-ebx
16722     #
16723     (emit-indent *(ebp+8) *Curr-block-depth)
16724     (write-buffered *(ebp+8) "8d/copy-address *(")
16725     # TODO: ensure inouts[0] is in a register and not dereferenced
16726 $translate-mu-index-stmt-with-array-in-register:emit-base:
16727     # ecx = stmt
16728     8b/-> *(ebp+0xc) 1/r32/ecx
16729     # var base/ebx: (addr var) = inouts[0]
16730     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16731     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16732     89/<- %ebx 0/r32/eax
16733     # print base->register " + "
16734     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
16735     (write-buffered *(ebp+8) %eax)
16736     (write-buffered *(ebp+8) " + ")
16737     # var index/edx: (addr var) = inouts[1]
16738     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16739     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
16740     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16741     89/<- %edx 0/r32/eax
16742     # if index->register
16743     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16744     {
16745       0f 84/jump-if-= break/disp32
16746 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
16747       # if index is an int
16748       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16749       (is-simple-mu-type? %eax 1)  # int => eax
16750       3d/compare-eax-and 0/imm32/false
16751       {
16752         0f 84/jump-if-= break/disp32
16753 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
16754         # print index->register "<<" log2(array-element-size(base)) " + 4) "
16755         # . index->register "<<"
16756         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16757         (write-buffered *(ebp+8) %eax)
16758         (write-buffered *(ebp+8) "<<")
16759         # . log2(array-element-size(base->type))
16760         # TODO: ensure size is a power of 2
16761         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16762         (num-shift-rights %eax)  # => eax
16763         (write-int32-hex-buffered *(ebp+8) %eax)
16764         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
16765       }
16766       # if index->type is any other atom, abort
16767       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16768       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16769       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16770       # if index has type (offset ...)
16771       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16772       (is-simple-mu-type? %eax 7)  # => eax
16773       3d/compare-eax-and 0/imm32/false
16774       {
16775         0f 84/jump-if-= break/disp32
16776         # print index->register
16777 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
16778         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16779         (write-buffered *(ebp+8) %eax)
16780       }
16781 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
16782       (write-buffered *(ebp+8) " + 4) ")
16783       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16784     }
16785     # otherwise if index is a literal
16786     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16787     (is-simple-mu-type? %eax 0)  # => eax
16788     3d/compare-eax-and 0/imm32/false
16789     {
16790       0f 84/jump-if-= break/disp32
16791 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
16792       # var index-value/edx: int = parse-hex-int(index->name)
16793       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16794       (parse-hex-int %eax)  # => eax
16795       89/<- %edx 0/r32/eax
16796       # offset = idx-value * array-element-size(base->type)
16797       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16798       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
16799       # offset += 4 for array size
16800       05/add-to-eax 4/imm32
16801       # TODO: check edx for overflow
16802       # print offset
16803       (write-int32-hex-buffered *(ebp+8) %eax)
16804       (write-buffered *(ebp+8) ") ")
16805       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
16806     }
16807     # otherwise abort
16808     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16809 $translate-mu-index-stmt-with-array-in-register:emit-output:
16810     # outputs[0] "/r32"
16811     8b/-> *(ebp+0xc) 1/r32/ecx
16812     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16813     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16814     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16815     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16816     (write-int32-hex-buffered *(ebp+8) *eax)
16817     (write-buffered *(ebp+8) "/r32\n")
16818 $translate-mu-index-stmt-with-array-in-register:end:
16819     # . restore registers
16820     5b/pop-to-ebx
16821     5a/pop-to-edx
16822     59/pop-to-ecx
16823     58/pop-to-eax
16824     # . epilogue
16825     89/<- %esp 5/r32/ebp
16826     5d/pop-to-ebp
16827     c3/return
16828 
16829 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16830     # . prologue
16831     55/push-ebp
16832     89/<- %ebp 4/r32/esp
16833     # . save registers
16834     50/push-eax
16835     51/push-ecx
16836     52/push-edx
16837     53/push-ebx
16838     #
16839     (emit-indent *(ebp+8) *Curr-block-depth)
16840     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
16841     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
16842     8b/-> *(ebp+0xc) 0/r32/eax
16843     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16844     89/<- %edx 0/r32/eax
16845     # var base/ecx: (addr var) = lookup(curr->value)
16846     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16847     89/<- %ecx 0/r32/eax
16848     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
16849     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
16850     # var index/edx: (handle var) = curr2->value
16851     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16852     89/<- %edx 0/r32/eax
16853     # if index->register
16854     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
16855     {
16856       0f 84/jump-if-= break/disp32
16857 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
16858       # if index is an int
16859       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16860       (is-simple-mu-type? %eax 1)  # int => eax
16861       3d/compare-eax-and 0/imm32/false
16862       {
16863         0f 84/jump-if-= break/disp32
16864 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
16865         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
16866         # . inouts[1]->register "<<"
16867         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16868         (write-buffered *(ebp+8) %eax)
16869         (write-buffered *(ebp+8) "<<")
16870         # . log2(array-element-size(base))
16871         # TODO: ensure size is a power of 2
16872         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16873         (num-shift-rights %eax)  # => eax
16874         (write-int32-hex-buffered *(ebp+8) %eax)
16875         #
16876         (write-buffered *(ebp+8) " + ")
16877         #
16878         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
16879         05/add-to-eax 4/imm32  # for array length
16880         (write-int32-hex-buffered *(ebp+8) %eax)
16881         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
16882       }
16883       # if index->type is any other atom, abort
16884       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16885       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
16886       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
16887       # if index has type (offset ...)
16888       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
16889       (is-simple-mu-type? %eax 7)  # => eax
16890       3d/compare-eax-and 0/imm32/false
16891       {
16892         0f 84/jump-if-= break/disp32
16893         # print index->register
16894 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
16895         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
16896         (write-buffered *(ebp+8) %eax)
16897       }
16898 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
16899       (write-buffered *(ebp+8) ") ")
16900       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16901     }
16902     # otherwise if index is a literal
16903     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
16904     (is-simple-mu-type? %eax 0)  # => eax
16905     3d/compare-eax-and 0/imm32/false
16906     {
16907       0f 84/jump-if-= break/disp32
16908 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
16909       # var idx-value/edx: int = parse-hex-int(index->name)
16910       (lookup *edx *(edx+4))  # Var-name Var-name => eax
16911       (parse-hex-int %eax)  # Var-name => eax
16912       89/<- %edx 0/r32/eax
16913       # offset = idx-value * array-element-size(base)
16914       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
16915       f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
16916       # offset += base->offset
16917       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
16918       # offset += 4 for array size
16919       05/add-to-eax 4/imm32
16920       # TODO: check edx for overflow
16921       # print offset
16922       (write-int32-hex-buffered *(ebp+8) %eax)
16923       (write-buffered *(ebp+8) ") ")
16924       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
16925     }
16926     # otherwise abort
16927     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
16928 $translate-mu-index-stmt-with-array-on-stack:emit-output:
16929     # outputs[0] "/r32"
16930     8b/-> *(ebp+0xc) 0/r32/eax
16931     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16932     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16933     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16934     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16935     (write-int32-hex-buffered *(ebp+8) *eax)
16936     (write-buffered *(ebp+8) "/r32\n")
16937 $translate-mu-index-stmt-with-array-on-stack:end:
16938     # . restore registers
16939     5b/pop-to-ebx
16940     5a/pop-to-edx
16941     59/pop-to-ecx
16942     58/pop-to-eax
16943     # . epilogue
16944     89/<- %esp 5/r32/ebp
16945     5d/pop-to-ebp
16946     c3/return
16947 
16948 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
16949     # . prologue
16950     55/push-ebp
16951     89/<- %ebp 4/r32/esp
16952     # . save registers
16953     50/push-eax
16954     51/push-ecx
16955     52/push-edx
16956     53/push-ebx
16957     #
16958     (emit-indent *(ebp+8) *Curr-block-depth)
16959     (write-buffered *(ebp+8) "69/multiply")
16960     # ecx = stmt
16961     8b/-> *(ebp+0xc) 1/r32/ecx
16962     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
16963     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16964     89/<- %ebx 0/r32/eax
16965 $translate-mu-compute-index-stmt:emit-index:
16966     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
16967     (emit-subx-var-as-rm32 *(ebp+8) %eax)
16968     (write-buffered *(ebp+8) Space)
16969 $translate-mu-compute-index-stmt:emit-elem-size:
16970     # var base/ebx: (addr var)
16971     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
16972     89/<- %ebx 0/r32/eax
16973     # print array-element-size(base)
16974     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
16975     (write-int32-hex-buffered *(ebp+8) %eax)
16976     (write-buffered *(ebp+8) "/imm32 ")
16977 $translate-mu-compute-index-stmt:emit-output:
16978     # outputs[0] "/r32"
16979     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16980     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
16981     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
16982     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
16983     (write-int32-hex-buffered *(ebp+8) *eax)
16984     (write-buffered *(ebp+8) "/r32\n")
16985 $translate-mu-compute-index-stmt:end:
16986     # . restore registers
16987     5b/pop-to-ebx
16988     5a/pop-to-edx
16989     59/pop-to-ecx
16990     58/pop-to-eax
16991     # . epilogue
16992     89/<- %esp 5/r32/ebp
16993     5d/pop-to-ebp
16994     c3/return
16995 
16996 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
16997     # . prologue
16998     55/push-ebp
16999     89/<- %ebp 4/r32/esp
17000     # . save registers
17001     50/push-eax
17002     51/push-ecx
17003     52/push-edx
17004     #
17005     (emit-indent *(ebp+8) *Curr-block-depth)
17006     (write-buffered *(ebp+8) "8d/copy-address ")
17007     # ecx = stmt
17008     8b/-> *(ebp+0xc) 1/r32/ecx
17009     # var offset/edx: int = get offset of stmt
17010     (mu-get-offset %ecx)  # => eax
17011     89/<- %edx 0/r32/eax
17012     # var base/eax: (addr var) = stmt->inouts->value
17013     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17014     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17015     # if base is in a register
17016     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
17017     {
17018       0f 84/jump-if-= break/disp32
17019 $translate-mu-get-stmt:emit-register-input:
17020       # emit "*(" base->register " + " offset ") "
17021       (write-buffered *(ebp+8) "*(")
17022       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17023       (write-buffered *(ebp+8) %eax)
17024       (write-buffered *(ebp+8) " + ")
17025       (write-int32-hex-buffered *(ebp+8) %edx)
17026       (write-buffered *(ebp+8) ") ")
17027       e9/jump $translate-mu-get-stmt:emit-output/disp32
17028     }
17029     # otherwise base is on the stack
17030     {
17031 $translate-mu-get-stmt:emit-stack-input:
17032       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
17033       (write-buffered *(ebp+8) "*(ebp+")
17034       03/add *(eax+0x14) 2/r32/edx  # Var-offset
17035       (write-int32-hex-buffered *(ebp+8) %edx)
17036       (write-buffered *(ebp+8) ") ")
17037       eb/jump $translate-mu-get-stmt:emit-output/disp8
17038     }
17039 $translate-mu-get-stmt:emit-output:
17040     # var output/eax: (addr var) = stmt->outputs->value
17041     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17042     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17043     # emit offset->register "/r32"
17044     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17045     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
17046     (write-int32-hex-buffered *(ebp+8) *eax)
17047     (write-buffered *(ebp+8) "/r32\n")
17048 $translate-mu-get-stmt:end:
17049     # . restore registers
17050     5a/pop-to-edx
17051     59/pop-to-ecx
17052     58/pop-to-eax
17053     # . epilogue
17054     89/<- %esp 5/r32/ebp
17055     5d/pop-to-ebp
17056     c3/return
17057 
17058 translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17059     # . prologue
17060     55/push-ebp
17061     89/<- %ebp 4/r32/esp
17062     # . save registers
17063     50/push-eax
17064     #
17065     (emit-indent *(ebp+8) *Curr-block-depth)
17066     (write-buffered *(ebp+8) "(copy-bytes")
17067     # eax = stmt
17068     8b/-> *(ebp+0xc) 0/r32/eax
17069     # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
17070     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17071     (emit-subx-call-operand *(ebp+8) %eax)
17072     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17073     (emit-subx-call-operand *(ebp+8) %eax)
17074     (write-buffered *(ebp+8) Space)
17075     (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
17076     (write-int32-hex-buffered *(ebp+8) %eax)
17077     (write-buffered *(ebp+8) ")\n")
17078 $translate-mu-copy-object-stmt:end:
17079     # . restore registers
17080     58/pop-to-eax
17081     # . epilogue
17082     89/<- %esp 5/r32/ebp
17083     5d/pop-to-ebp
17084     c3/return
17085 
17086 translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17087     # . prologue
17088     55/push-ebp
17089     89/<- %ebp 4/r32/esp
17090     # . save registers
17091     50/push-eax
17092     56/push-esi
17093     57/push-edi
17094     # esi = stmt
17095     8b/-> *(ebp+0xc) 6/r32/esi
17096     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17097     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17098     89/<- %edi 0/r32/eax
17099     #
17100     (emit-indent *(ebp+8) *Curr-block-depth)
17101     (write-buffered *(ebp+8) "(allocate Heap ")
17102     (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17103     (write-int32-hex-buffered *(ebp+8) %eax)
17104     (emit-subx-call-operand *(ebp+8) %edi)
17105     (write-buffered *(ebp+8) ")\n")
17106 $translate-mu-allocate-stmt:end:
17107     # . restore registers
17108     5f/pop-to-edi
17109     5e/pop-to-esi
17110     58/pop-to-eax
17111     # . epilogue
17112     89/<- %esp 5/r32/ebp
17113     5d/pop-to-ebp
17114     c3/return
17115 
17116 addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17117     # . prologue
17118     55/push-ebp
17119     89/<- %ebp 4/r32/esp
17120     # var t/eax: (addr type-tree) = s->value->type
17121     8b/-> *(ebp+8) 0/r32/eax
17122     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17123     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17124     # TODO: check eax != 0
17125     # TODO: check !t->is-atom?
17126     # TODO: check t->left == addr
17127     # t = t->right
17128 $addr-handle-payload-size:skip-addr:
17129     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17130     # TODO: check eax != 0
17131     # TODO: check !t->is-atom?
17132     # TODO: check t->left == handle
17133     # t = t->right
17134 $addr-handle-payload-size:skip-handle:
17135     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17136     # TODO: check eax != 0
17137     # if !t->is-atom? t = t->left
17138     81 7/subop/compare *eax 0/imm32/false
17139     {
17140       75/jump-if-!= break/disp8
17141       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17142     }
17143     # TODO: check t->is-atom?
17144     # return size(t->value)
17145     (size-of-type-id *(eax+4))  # Type-tree-value => eax
17146 $addr-handle-payload-size:end:
17147     # . epilogue
17148     89/<- %esp 5/r32/ebp
17149     5d/pop-to-ebp
17150     c3/return
17151 
17152 addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17153     # . prologue
17154     55/push-ebp
17155     89/<- %ebp 4/r32/esp
17156     # var t/eax: (addr type-tree) = s->value->type
17157     8b/-> *(ebp+8) 0/r32/eax
17158     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17159     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17160     # TODO: check eax != 0
17161     # TODO: check !t->is-atom?
17162     # TODO: check t->left == addr
17163     # t = t->right
17164 $addr-payload-size:skip-addr:
17165     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17166     # TODO: check eax != 0
17167     # if !t->is-atom? t = t->left
17168     81 7/subop/compare *eax 0/imm32/false
17169     {
17170       75/jump-if-!= break/disp8
17171       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17172     }
17173     # TODO: check t->is-atom?
17174     # return size(t->value)
17175     (size-of-type-id *(eax+4))  # Type-tree-value => eax
17176 $addr-payload-size:end:
17177     # . epilogue
17178     89/<- %esp 5/r32/ebp
17179     5d/pop-to-ebp
17180     c3/return
17181 
17182 translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17183     # . prologue
17184     55/push-ebp
17185     89/<- %ebp 4/r32/esp
17186     # . save registers
17187     50/push-eax
17188     51/push-ecx
17189     56/push-esi
17190     57/push-edi
17191     # esi = stmt
17192     8b/-> *(ebp+0xc) 6/r32/esi
17193     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17194     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17195     89/<- %edi 0/r32/eax
17196     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
17197     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
17198     89/<- %ecx 0/r32/eax
17199     #
17200     (emit-indent *(ebp+8) *Curr-block-depth)
17201     (write-buffered *(ebp+8) "(allocate-array2 Heap ")
17202     (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17203     (write-int32-hex-buffered *(ebp+8) %eax)
17204     (emit-subx-call-operand *(ebp+8) %ecx)
17205     (emit-subx-call-operand *(ebp+8) %edi)
17206     (write-buffered *(ebp+8) ")\n")
17207 $translate-mu-populate-stmt:end:
17208     # . restore registers
17209     5f/pop-to-edi
17210     5e/pop-to-esi
17211     59/pop-to-ecx
17212     58/pop-to-eax
17213     # . epilogue
17214     89/<- %esp 5/r32/ebp
17215     5d/pop-to-ebp
17216     c3/return
17217 
17218 translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17219     # . prologue
17220     55/push-ebp
17221     89/<- %ebp 4/r32/esp
17222     # . save registers
17223     50/push-eax
17224     51/push-ecx
17225     56/push-esi
17226     57/push-edi
17227     # esi = stmt
17228     8b/-> *(ebp+0xc) 6/r32/esi
17229     # var target/edi: (addr stmt-var) = stmt->inouts[0]
17230     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17231     89/<- %edi 0/r32/eax
17232     # var len/ecx: (addr stmt-var) = stmt->inouts[1]
17233     (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
17234     89/<- %ecx 0/r32/eax
17235     #
17236     (emit-indent *(ebp+8) *Curr-block-depth)
17237     (write-buffered *(ebp+8) "(new-stream Heap ")
17238     (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17239     (write-int32-hex-buffered *(ebp+8) %eax)
17240     (emit-subx-call-operand *(ebp+8) %ecx)
17241     (emit-subx-call-operand *(ebp+8) %edi)
17242     (write-buffered *(ebp+8) ")\n")
17243 $translate-mu-populate-stream-stmt:end:
17244     # . restore registers
17245     5f/pop-to-edi
17246     5e/pop-to-esi
17247     59/pop-to-ecx
17248     58/pop-to-eax
17249     # . epilogue
17250     89/<- %esp 5/r32/ebp
17251     5d/pop-to-ebp
17252     c3/return
17253 
17254 translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17255     # . prologue
17256     55/push-ebp
17257     89/<- %ebp 4/r32/esp
17258     # . save registers
17259     50/push-eax
17260     51/push-ecx
17261     56/push-esi
17262     57/push-edi
17263     # esi = stmt
17264     8b/-> *(ebp+0xc) 6/r32/esi
17265     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17266     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17267     89/<- %ecx 0/r32/eax
17268     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17269     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17270     89/<- %edi 0/r32/eax
17271     #
17272     (emit-indent *(ebp+8) *Curr-block-depth)
17273     (write-buffered *(ebp+8) "(read-from-stream")
17274     (emit-subx-call-operand *(ebp+8) %ecx)
17275     (emit-subx-call-operand *(ebp+8) %edi)
17276     (write-buffered *(ebp+8) Space)
17277     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17278     (write-int32-hex-buffered *(ebp+8) %eax)
17279     (write-buffered *(ebp+8) ")\n")
17280 $translate-mu-read-from-stream-stmt:end:
17281     # . restore registers
17282     5f/pop-to-edi
17283     5e/pop-to-esi
17284     59/pop-to-ecx
17285     58/pop-to-eax
17286     # . epilogue
17287     89/<- %esp 5/r32/ebp
17288     5d/pop-to-ebp
17289     c3/return
17290 
17291 translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17292     # . prologue
17293     55/push-ebp
17294     89/<- %ebp 4/r32/esp
17295     # . save registers
17296     50/push-eax
17297     51/push-ecx
17298     56/push-esi
17299     57/push-edi
17300     # esi = stmt
17301     8b/-> *(ebp+0xc) 6/r32/esi
17302     # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
17303     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17304     89/<- %ecx 0/r32/eax
17305     # var target/edi: (addr stmt-var) = stmt->inouts[1]
17306     (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
17307     89/<- %edi 0/r32/eax
17308     #
17309     (emit-indent *(ebp+8) *Curr-block-depth)
17310     (write-buffered *(ebp+8) "(write-to-stream")
17311     (emit-subx-call-operand *(ebp+8) %ecx)
17312     (flush *(ebp+8))
17313     (emit-subx-call-operand *(ebp+8) %edi)
17314     (flush *(ebp+8))
17315     (write-buffered *(ebp+8) Space)
17316     (flush *(ebp+8))
17317     (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
17318     (write-int32-hex-buffered *(ebp+8) %eax)
17319     (write-buffered *(ebp+8) ")\n")
17320 $translate-mu-write-to-stream-stmt:end:
17321     # . restore registers
17322     5f/pop-to-edi
17323     5e/pop-to-esi
17324     59/pop-to-ecx
17325     58/pop-to-eax
17326     # . epilogue
17327     89/<- %esp 5/r32/ebp
17328     5d/pop-to-ebp
17329     c3/return
17330 
17331 addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17332     # . prologue
17333     55/push-ebp
17334     89/<- %ebp 4/r32/esp
17335     # var t/eax: (addr type-tree) = s->value->type
17336     8b/-> *(ebp+8) 0/r32/eax
17337     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17338     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17339     # TODO: check eax != 0
17340     # TODO: check !t->is-atom?
17341     # TODO: check t->left == addr
17342     # t = t->right
17343 $addr-handle-array-payload-size:skip-addr:
17344     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17345     # TODO: check eax != 0
17346     # TODO: check !t->is-atom?
17347     # TODO: check t->left == handle
17348     # t = t->right
17349 $addr-handle-array-payload-size:skip-handle:
17350     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17351     # TODO: check eax != 0
17352     # TODO: check !t->is-atom?
17353     # TODO: check t->left == array
17354     # t = t->right
17355 $addr-handle-array-payload-size:skip-array:
17356     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17357     # TODO: check eax != 0
17358     # if !t->is-atom? t = t->left
17359     81 7/subop/compare *eax 0/imm32/false
17360     {
17361       75/jump-if-!= break/disp8
17362       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17363     }
17364 $addr-handle-array-payload-size:compute-size:
17365     # TODO: check t->is-atom?
17366     # return size(t->value)
17367     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17368 $addr-handle-array-payload-size:end:
17369     # . epilogue
17370     89/<- %esp 5/r32/ebp
17371     5d/pop-to-ebp
17372     c3/return
17373 
17374 addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
17375     # . prologue
17376     55/push-ebp
17377     89/<- %ebp 4/r32/esp
17378     # var t/eax: (addr type-tree) = s->value->type
17379     8b/-> *(ebp+8) 0/r32/eax
17380     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17381     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
17382     # TODO: check eax != 0
17383     # TODO: check !t->is-atom?
17384     # TODO: check t->left == addr
17385     # t = t->right
17386 $addr-handle-stream-payload-size:skip-addr:
17387     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17388     # TODO: check eax != 0
17389     # TODO: check !t->is-atom?
17390     # TODO: check t->left == handle
17391     # t = t->right
17392 $addr-handle-stream-payload-size:skip-handle:
17393     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17394     # TODO: check eax != 0
17395     # TODO: check !t->is-atom?
17396     # TODO: check t->left == stream
17397     # t = t->right
17398 $addr-handle-stream-payload-size:skip-stream:
17399     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
17400     # TODO: check eax != 0
17401     # if !t->is-atom? t = t->left
17402     81 7/subop/compare *eax 0/imm32/false
17403     {
17404       75/jump-if-!= break/disp8
17405       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
17406     }
17407 $addr-handle-stream-payload-size:compute-size:
17408     # TODO: check t->is-atom?
17409     # return size(t->value)
17410     (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
17411 $addr-handle-stream-payload-size:end:
17412     # . epilogue
17413     89/<- %esp 5/r32/ebp
17414     5d/pop-to-ebp
17415     c3/return
17416 
17417 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
17418     # precondition: n is positive
17419     # . prologue
17420     55/push-ebp
17421     89/<- %ebp 4/r32/esp
17422     # eax = n
17423     8b/-> *(ebp+8) 0/r32/eax
17424     # if (n < 0) abort
17425     3d/compare-eax-with 0/imm32
17426     0f 8c/jump-if-< $power-of-2?:abort/disp32
17427     # var tmp/eax: int = n-1
17428     48/decrement-eax
17429     # var tmp2/eax: int = n & tmp
17430     23/and-> *(ebp+8) 0/r32/eax
17431     # return (tmp2 == 0)
17432     3d/compare-eax-and 0/imm32
17433     0f 94/set-byte-if-= %al
17434     81 4/subop/and %eax 0xff/imm32
17435 $power-of-2?:end:
17436     # . epilogue
17437     89/<- %esp 5/r32/ebp
17438     5d/pop-to-ebp
17439     c3/return
17440 
17441 $power-of-2?:abort:
17442     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
17443     (flush *(ebp+0xc))
17444     (stop *(ebp+0x10) 1)
17445     # never gets here
17446 
17447 num-shift-rights:  # n: int -> result/eax: int
17448     # precondition: n is a positive power of 2
17449     # . prologue
17450     55/push-ebp
17451     89/<- %ebp 4/r32/esp
17452     # . save registers
17453     51/push-ecx
17454     # var curr/ecx: int = n
17455     8b/-> *(ebp+8) 1/r32/ecx
17456     # result = 0
17457     b8/copy-to-eax 0/imm32
17458     {
17459       # if (curr <= 1) break
17460       81 7/subop/compare %ecx 1/imm32
17461       7e/jump-if-<= break/disp8
17462       40/increment-eax
17463       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
17464       eb/jump loop/disp8
17465     }
17466 $num-shift-rights:end:
17467     # . restore registers
17468     59/pop-to-ecx
17469     # . epilogue
17470     89/<- %esp 5/r32/ebp
17471     5d/pop-to-ebp
17472     c3/return
17473 
17474 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
17475     # . prologue
17476     55/push-ebp
17477     89/<- %ebp 4/r32/esp
17478     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
17479     8b/-> *(ebp+8) 0/r32/eax
17480     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17481     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17482     # var output-var/eax: (addr var) = second-inout->value
17483     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17484 #?     (write-buffered Stderr "mu-get-offset: ")
17485 #?     (write-int32-hex-buffered Stderr %eax)
17486 #?     (write-buffered Stderr " name: ")
17487 #?     50/push-eax
17488 #?     (lookup *eax *(eax+4))  # Var-name
17489 #?     (write-buffered Stderr %eax)
17490 #?     58/pop-to-eax
17491 #?     (write-buffered Stderr Newline)
17492 #?     (flush Stderr)
17493     # return output-var->stack-offset
17494     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
17495 #?     (write-buffered Stderr "=> ")
17496 #?     (write-int32-hex-buffered Stderr %eax)
17497 #?     (write-buffered Stderr Newline)
17498 #?     (flush Stderr)
17499 $emit-get-offset:end:
17500     # . epilogue
17501     89/<- %esp 5/r32/ebp
17502     5d/pop-to-ebp
17503     c3/return
17504 
17505 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)
17506     # . prologue
17507     55/push-ebp
17508     89/<- %ebp 4/r32/esp
17509     # . save registers
17510     50/push-eax
17511     51/push-ecx
17512     56/push-esi
17513     # esi = block
17514     8b/-> *(ebp+0xc) 6/r32/esi
17515     # block->var->block-depth = *Curr-block-depth
17516     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17517     8b/-> *Curr-block-depth 1/r32/ecx
17518     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
17519     # var stmts/eax: (addr list stmt) = lookup(block->statements)
17520     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17521     #
17522     {
17523 $emit-subx-block:check-empty:
17524       3d/compare-eax-and 0/imm32
17525       0f 84/jump-if-= break/disp32
17526       (emit-indent *(ebp+8) *Curr-block-depth)
17527       (write-buffered *(ebp+8) "{\n")
17528       # var v/ecx: (addr var) = lookup(block->var)
17529       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
17530       89/<- %ecx 0/r32/eax
17531       #
17532       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17533       (write-buffered *(ebp+8) %eax)
17534       (write-buffered *(ebp+8) ":loop:\n")
17535       ff 0/subop/increment *Curr-block-depth
17536       (push *(ebp+0x10) *(esi+0xc))  # Block-var
17537       (push *(ebp+0x10) *(esi+0x10))  # Block-var
17538       (push *(ebp+0x10) 0)  # false
17539       # emit block->statements
17540       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
17541       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
17542       (pop *(ebp+0x10))  # => eax
17543       (pop *(ebp+0x10))  # => eax
17544       (pop *(ebp+0x10))  # => eax
17545       ff 1/subop/decrement *Curr-block-depth
17546       (emit-indent *(ebp+8) *Curr-block-depth)
17547       (write-buffered *(ebp+8) "}\n")
17548       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
17549       (write-buffered *(ebp+8) %eax)
17550       (write-buffered *(ebp+8) ":break:\n")
17551     }
17552 $emit-subx-block:end:
17553     # . restore registers
17554     5e/pop-to-esi
17555     59/pop-to-ecx
17556     58/pop-to-eax
17557     # . epilogue
17558     89/<- %esp 5/r32/ebp
17559     5d/pop-to-ebp
17560     c3/return
17561 
17562 # Primitives supported
17563 # See mu_instructions for a summary of this linked-list data structure.
17564 #
17565 # For each operation, put variants with hard-coded registers before flexible ones.
17566 #
17567 # Unfortunately, our restrictions on addresses require that various fields in
17568 # primitives be handles, which complicates these definitions.
17569 #   - we need to insert dummy fields all over the place for fake alloc-ids
17570 #   - we can't use our syntax sugar of quoted literals for string fields
17571 #
17572 # Fake alloc-ids are needed because our type definitions up top require
17573 # handles but it's clearer to statically allocate these long-lived objects.
17574 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
17575 #
17576 # Every 'object' below starts with a fake alloc-id. It may also contain other
17577 # fake alloc-ids for various handle fields.
17578 #
17579 # I think of objects starting with a fake alloc-id as having type 'payload'.
17580 # It's not really intended to be created dynamically; for that use `allocate`
17581 # as usual.
17582 #
17583 # Idea for a notation to simplify such definitions:
17584 #   _Primitive-increment-eax:  # (payload primitive)
17585 #     0x11/alloc-id:fake:payload
17586 #     0x11 @(0x11 "increment")  # name
17587 #     0 0                       # inouts
17588 #     0x11 @(0x11/payload
17589 #            0x11 @(0x11/payload  # List-value
17590 #                   0 0             # Var-name
17591 #                   0x11 @(0x11     # Var-type
17592 #                          1/is-atom
17593 #                          1/value 0/unused   # Type-tree-left
17594 #                          0 0                # Type-tree-right
17595 #                         )
17596 #                   1               # block-depth
17597 #                   0               # stack-offset
17598 #                   0x11 @(0x11 "eax")  # Var-register
17599 #                  )
17600 #            0 0)                 # List-next
17601 #     ...
17602 #     _Primitive-increment-ecx/imm32/next
17603 #   ...
17604 # Awfully complex and non-obvious. But also clearly signals there's something
17605 # to learn here, so may be worth trying.
17606 #
17607 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
17608 #
17609 # For now we'll continue to just use comments and manually ensure they stay up
17610 # to date.
17611 == data
17612 Primitives:  # (addr primitive)
17613 # - increment/decrement
17614 _Primitive-increment-eax:  # (addr primitive)
17615     # var/eax <- increment => 40/increment-eax
17616     0x11/imm32/alloc-id:fake
17617     _string-increment/imm32/name
17618     0/imm32/no-inouts
17619     0/imm32/no-inouts
17620     0x11/imm32/alloc-id:fake
17621     Single-int-var-in-eax/imm32/outputs
17622     0x11/imm32/alloc-id:fake
17623     _string_40_increment_eax/imm32/subx-name
17624     0/imm32/no-rm32
17625     0/imm32/no-r32
17626     0/imm32/no-imm32
17627     0/imm32/no-imm8
17628     0/imm32/no-disp32
17629     0/imm32/output-is-write-only
17630     0x11/imm32/alloc-id:fake
17631     _Primitive-increment-ecx/imm32/next
17632 _Primitive-increment-ecx:  # (payload primitive)
17633     0x11/imm32/alloc-id:fake:payload
17634     # var/ecx <- increment => 41/increment-ecx
17635     0x11/imm32/alloc-id:fake
17636     _string-increment/imm32/name
17637     0/imm32/no-inouts
17638     0/imm32/no-inouts
17639     0x11/imm32/alloc-id:fake
17640     Single-int-var-in-ecx/imm32/outputs
17641     0x11/imm32/alloc-id:fake
17642     _string_41_increment_ecx/imm32/subx-name
17643     0/imm32/no-rm32
17644     0/imm32/no-r32
17645     0/imm32/no-imm32
17646     0/imm32/no-imm8
17647     0/imm32/no-disp32
17648     0/imm32/output-is-write-only
17649     0x11/imm32/alloc-id:fake
17650     _Primitive-increment-edx/imm32/next
17651 _Primitive-increment-edx:  # (payload primitive)
17652     0x11/imm32/alloc-id:fake:payload
17653     # var/edx <- increment => 42/increment-edx
17654     0x11/imm32/alloc-id:fake
17655     _string-increment/imm32/name
17656     0/imm32/no-inouts
17657     0/imm32/no-inouts
17658     0x11/imm32/alloc-id:fake
17659     Single-int-var-in-edx/imm32/outputs
17660     0x11/imm32/alloc-id:fake
17661     _string_42_increment_edx/imm32/subx-name
17662     0/imm32/no-rm32
17663     0/imm32/no-r32
17664     0/imm32/no-imm32
17665     0/imm32/no-imm8
17666     0/imm32/no-disp32
17667     0/imm32/output-is-write-only
17668     0x11/imm32/alloc-id:fake
17669     _Primitive-increment-ebx/imm32/next
17670 _Primitive-increment-ebx:  # (payload primitive)
17671     0x11/imm32/alloc-id:fake:payload
17672     # var/ebx <- increment => 43/increment-ebx
17673     0x11/imm32/alloc-id:fake
17674     _string-increment/imm32/name
17675     0/imm32/no-inouts
17676     0/imm32/no-inouts
17677     0x11/imm32/alloc-id:fake
17678     Single-int-var-in-ebx/imm32/outputs
17679     0x11/imm32/alloc-id:fake
17680     _string_43_increment_ebx/imm32/subx-name
17681     0/imm32/no-rm32
17682     0/imm32/no-r32
17683     0/imm32/no-imm32
17684     0/imm32/no-imm8
17685     0/imm32/no-disp32
17686     0/imm32/output-is-write-only
17687     0x11/imm32/alloc-id:fake
17688     _Primitive-increment-esi/imm32/next
17689 _Primitive-increment-esi:  # (payload primitive)
17690     0x11/imm32/alloc-id:fake:payload
17691     # var/esi <- increment => 46/increment-esi
17692     0x11/imm32/alloc-id:fake
17693     _string-increment/imm32/name
17694     0/imm32/no-inouts
17695     0/imm32/no-inouts
17696     0x11/imm32/alloc-id:fake
17697     Single-int-var-in-esi/imm32/outputs
17698     0x11/imm32/alloc-id:fake
17699     _string_46_increment_esi/imm32/subx-name
17700     0/imm32/no-rm32
17701     0/imm32/no-r32
17702     0/imm32/no-imm32
17703     0/imm32/no-imm8
17704     0/imm32/no-disp32
17705     0/imm32/output-is-write-only
17706     0x11/imm32/alloc-id:fake
17707     _Primitive-increment-edi/imm32/next
17708 _Primitive-increment-edi:  # (payload primitive)
17709     0x11/imm32/alloc-id:fake:payload
17710     # var/edi <- increment => 47/increment-edi
17711     0x11/imm32/alloc-id:fake
17712     _string-increment/imm32/name
17713     0/imm32/no-inouts
17714     0/imm32/no-inouts
17715     0x11/imm32/alloc-id:fake
17716     Single-int-var-in-edi/imm32/outputs
17717     0x11/imm32/alloc-id:fake
17718     _string_47_increment_edi/imm32/subx-name
17719     0/imm32/no-rm32
17720     0/imm32/no-r32
17721     0/imm32/no-imm32
17722     0/imm32/no-imm8
17723     0/imm32/no-disp32
17724     0/imm32/output-is-write-only
17725     0x11/imm32/alloc-id:fake
17726     _Primitive-decrement-eax/imm32/next
17727 _Primitive-decrement-eax:  # (payload primitive)
17728     0x11/imm32/alloc-id:fake:payload
17729     # var/eax <- decrement => 48/decrement-eax
17730     0x11/imm32/alloc-id:fake
17731     _string-decrement/imm32/name
17732     0/imm32/no-inouts
17733     0/imm32/no-inouts
17734     0x11/imm32/alloc-id:fake
17735     Single-int-var-in-eax/imm32/outputs
17736     0x11/imm32/alloc-id:fake
17737     _string_48_decrement_eax/imm32/subx-name
17738     0/imm32/no-rm32
17739     0/imm32/no-r32
17740     0/imm32/no-imm32
17741     0/imm32/no-imm8
17742     0/imm32/no-disp32
17743     0/imm32/output-is-write-only
17744     0x11/imm32/alloc-id:fake
17745     _Primitive-decrement-ecx/imm32/next
17746 _Primitive-decrement-ecx:  # (payload primitive)
17747     0x11/imm32/alloc-id:fake:payload
17748     # var/ecx <- decrement => 49/decrement-ecx
17749     0x11/imm32/alloc-id:fake
17750     _string-decrement/imm32/name
17751     0/imm32/no-inouts
17752     0/imm32/no-inouts
17753     0x11/imm32/alloc-id:fake
17754     Single-int-var-in-ecx/imm32/outputs
17755     0x11/imm32/alloc-id:fake
17756     _string_49_decrement_ecx/imm32/subx-name
17757     0/imm32/no-rm32
17758     0/imm32/no-r32
17759     0/imm32/no-imm32
17760     0/imm32/no-imm8
17761     0/imm32/no-disp32
17762     0/imm32/output-is-write-only
17763     0x11/imm32/alloc-id:fake
17764     _Primitive-decrement-edx/imm32/next
17765 _Primitive-decrement-edx:  # (payload primitive)
17766     0x11/imm32/alloc-id:fake:payload
17767     # var/edx <- decrement => 4a/decrement-edx
17768     0x11/imm32/alloc-id:fake
17769     _string-decrement/imm32/name
17770     0/imm32/no-inouts
17771     0/imm32/no-inouts
17772     0x11/imm32/alloc-id:fake
17773     Single-int-var-in-edx/imm32/outputs
17774     0x11/imm32/alloc-id:fake
17775     _string_4a_decrement_edx/imm32/subx-name
17776     0/imm32/no-rm32
17777     0/imm32/no-r32
17778     0/imm32/no-imm32
17779     0/imm32/no-imm8
17780     0/imm32/no-disp32
17781     0/imm32/output-is-write-only
17782     0x11/imm32/alloc-id:fake
17783     _Primitive-decrement-ebx/imm32/next
17784 _Primitive-decrement-ebx:  # (payload primitive)
17785     0x11/imm32/alloc-id:fake:payload
17786     # var/ebx <- decrement => 4b/decrement-ebx
17787     0x11/imm32/alloc-id:fake
17788     _string-decrement/imm32/name
17789     0/imm32/no-inouts
17790     0/imm32/no-inouts
17791     0x11/imm32/alloc-id:fake
17792     Single-int-var-in-ebx/imm32/outputs
17793     0x11/imm32/alloc-id:fake
17794     _string_4b_decrement_ebx/imm32/subx-name
17795     0/imm32/no-rm32
17796     0/imm32/no-r32
17797     0/imm32/no-imm32
17798     0/imm32/no-imm8
17799     0/imm32/no-disp32
17800     0/imm32/output-is-write-only
17801     0x11/imm32/alloc-id:fake
17802     _Primitive-decrement-esi/imm32/next
17803 _Primitive-decrement-esi:  # (payload primitive)
17804     0x11/imm32/alloc-id:fake:payload
17805     # var/esi <- decrement => 4e/decrement-esi
17806     0x11/imm32/alloc-id:fake
17807     _string-decrement/imm32/name
17808     0/imm32/no-inouts
17809     0/imm32/no-inouts
17810     0x11/imm32/alloc-id:fake
17811     Single-int-var-in-esi/imm32/outputs
17812     0x11/imm32/alloc-id:fake
17813     _string_4e_decrement_esi/imm32/subx-name
17814     0/imm32/no-rm32
17815     0/imm32/no-r32
17816     0/imm32/no-imm32
17817     0/imm32/no-imm8
17818     0/imm32/no-disp32
17819     0/imm32/output-is-write-only
17820     0x11/imm32/alloc-id:fake
17821     _Primitive-decrement-edi/imm32/next
17822 _Primitive-decrement-edi:  # (payload primitive)
17823     0x11/imm32/alloc-id:fake:payload
17824     # var/edi <- decrement => 4f/decrement-edi
17825     0x11/imm32/alloc-id:fake
17826     _string-decrement/imm32/name
17827     0/imm32/no-inouts
17828     0/imm32/no-inouts
17829     0x11/imm32/alloc-id:fake
17830     Single-int-var-in-edi/imm32/outputs
17831     0x11/imm32/alloc-id:fake
17832     _string_4f_decrement_edi/imm32/subx-name
17833     0/imm32/no-rm32
17834     0/imm32/no-r32
17835     0/imm32/no-imm32
17836     0/imm32/no-imm8
17837     0/imm32/no-disp32
17838     0/imm32/output-is-write-only
17839     0x11/imm32/alloc-id:fake
17840     _Primitive-increment-mem/imm32/next
17841 _Primitive-increment-mem:  # (payload primitive)
17842     0x11/imm32/alloc-id:fake:payload
17843     # increment var => ff 0/subop/increment *(ebp+__)
17844     0x11/imm32/alloc-id:fake
17845     _string-increment/imm32/name
17846     0x11/imm32/alloc-id:fake
17847     Single-int-var-in-mem/imm32/inouts
17848     0/imm32/no-outputs
17849     0/imm32/no-outputs
17850     0x11/imm32/alloc-id:fake
17851     _string_ff_subop_increment/imm32/subx-name
17852     1/imm32/rm32-is-first-inout
17853     0/imm32/no-r32
17854     0/imm32/no-imm32
17855     0/imm32/no-imm8
17856     0/imm32/no-disp32
17857     0/imm32/output-is-write-only
17858     0x11/imm32/alloc-id:fake
17859     _Primitive-increment-reg/imm32/next
17860 _Primitive-increment-reg:  # (payload primitive)
17861     0x11/imm32/alloc-id:fake:payload
17862     # var/reg <- increment => ff 0/subop/increment %__
17863     0x11/imm32/alloc-id:fake
17864     _string-increment/imm32/name
17865     0/imm32/no-inouts
17866     0/imm32/no-inouts
17867     0x11/imm32/alloc-id:fake
17868     Single-int-var-in-some-register/imm32/outputs
17869     0x11/imm32/alloc-id:fake
17870     _string_ff_subop_increment/imm32/subx-name
17871     3/imm32/rm32-is-first-output
17872     0/imm32/no-r32
17873     0/imm32/no-imm32
17874     0/imm32/no-imm8
17875     0/imm32/no-disp32
17876     0/imm32/output-is-write-only
17877     0x11/imm32/alloc-id:fake
17878     _Primitive-decrement-mem/imm32/next
17879 _Primitive-decrement-mem:  # (payload primitive)
17880     0x11/imm32/alloc-id:fake:payload
17881     # decrement var => ff 1/subop/decrement *(ebp+__)
17882     0x11/imm32/alloc-id:fake
17883     _string-decrement/imm32/name
17884     0x11/imm32/alloc-id:fake
17885     Single-int-var-in-mem/imm32/inouts
17886     0/imm32/no-outputs
17887     0/imm32/no-outputs
17888     0x11/imm32/alloc-id:fake
17889     _string_ff_subop_decrement/imm32/subx-name
17890     1/imm32/rm32-is-first-inout
17891     0/imm32/no-r32
17892     0/imm32/no-imm32
17893     0/imm32/no-imm8
17894     0/imm32/no-disp32
17895     0/imm32/output-is-write-only
17896     0x11/imm32/alloc-id:fake
17897     _Primitive-decrement-reg/imm32/next
17898 _Primitive-decrement-reg:  # (payload primitive)
17899     0x11/imm32/alloc-id:fake:payload
17900     # var/reg <- decrement => ff 1/subop/decrement %__
17901     0x11/imm32/alloc-id:fake
17902     _string-decrement/imm32/name
17903     0/imm32/no-inouts
17904     0/imm32/no-inouts
17905     0x11/imm32/alloc-id:fake
17906     Single-int-var-in-some-register/imm32/outputs
17907     0x11/imm32/alloc-id:fake
17908     _string_ff_subop_decrement/imm32/subx-name
17909     3/imm32/rm32-is-first-output
17910     0/imm32/no-r32
17911     0/imm32/no-imm32
17912     0/imm32/no-imm8
17913     0/imm32/no-disp32
17914     0/imm32/output-is-write-only
17915     0x11/imm32/alloc-id:fake
17916     _Primitive-add-to-eax/imm32/next
17917 # - add
17918 _Primitive-add-to-eax:  # (payload primitive)
17919     0x11/imm32/alloc-id:fake:payload
17920     # var/eax <- add lit => 05/add-to-eax lit/imm32
17921     0x11/imm32/alloc-id:fake
17922     _string-add/imm32/name
17923     0x11/imm32/alloc-id:fake
17924     Single-lit-var/imm32/inouts
17925     0x11/imm32/alloc-id:fake
17926     Single-int-var-in-eax/imm32/outputs
17927     0x11/imm32/alloc-id:fake
17928     _string_05_add_to_eax/imm32/subx-name
17929     0/imm32/no-rm32
17930     0/imm32/no-r32
17931     1/imm32/imm32-is-first-inout
17932     0/imm32/no-imm8
17933     0/imm32/no-disp32
17934     0/imm32/output-is-write-only
17935     0x11/imm32/alloc-id:fake
17936     _Primitive-add-reg-to-reg/imm32/next
17937 _Primitive-add-reg-to-reg:  # (payload primitive)
17938     0x11/imm32/alloc-id:fake:payload
17939     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
17940     0x11/imm32/alloc-id:fake
17941     _string-add/imm32/name
17942     0x11/imm32/alloc-id:fake
17943     Single-int-var-in-some-register/imm32/inouts
17944     0x11/imm32/alloc-id:fake
17945     Single-int-var-in-some-register/imm32/outputs
17946     0x11/imm32/alloc-id:fake
17947     _string_01_add_to/imm32/subx-name
17948     3/imm32/rm32-is-first-output
17949     1/imm32/r32-is-first-inout
17950     0/imm32/no-imm32
17951     0/imm32/no-imm8
17952     0/imm32/no-disp32
17953     0/imm32/output-is-write-only
17954     0x11/imm32/alloc-id:fake
17955     _Primitive-add-reg-to-mem/imm32/next
17956 _Primitive-add-reg-to-mem:  # (payload primitive)
17957     0x11/imm32/alloc-id:fake:payload
17958     # add-to var1 var2/reg => 01/add-to var1 var2/r32
17959     0x11/imm32/alloc-id:fake
17960     _string-add-to/imm32/name
17961     0x11/imm32/alloc-id:fake
17962     Two-args-int-stack-int-reg/imm32/inouts
17963     0/imm32/no-outputs
17964     0/imm32/no-outputs
17965     0x11/imm32/alloc-id:fake
17966     _string_01_add_to/imm32/subx-name
17967     1/imm32/rm32-is-first-inout
17968     2/imm32/r32-is-second-inout
17969     0/imm32/no-imm32
17970     0/imm32/no-imm8
17971     0/imm32/no-disp32
17972     0/imm32/output-is-write-only
17973     0x11/imm32/alloc-id:fake
17974     _Primitive-add-mem-to-reg/imm32/next
17975 _Primitive-add-mem-to-reg:  # (payload primitive)
17976     0x11/imm32/alloc-id:fake:payload
17977     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
17978     0x11/imm32/alloc-id:fake
17979     _string-add/imm32/name
17980     0x11/imm32/alloc-id:fake
17981     Single-int-var-in-mem/imm32/inouts
17982     0x11/imm32/alloc-id:fake
17983     Single-int-var-in-some-register/imm32/outputs
17984     0x11/imm32/alloc-id:fake
17985     _string_03_add/imm32/subx-name
17986     1/imm32/rm32-is-first-inout
17987     3/imm32/r32-is-first-output
17988     0/imm32/no-imm32
17989     0/imm32/no-imm8
17990     0/imm32/no-disp32
17991     0/imm32/output-is-write-only
17992     0x11/imm32/alloc-id:fake
17993     _Primitive-add-lit-to-reg/imm32/next
17994 _Primitive-add-lit-to-reg:  # (payload primitive)
17995     0x11/imm32/alloc-id:fake:payload
17996     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
17997     0x11/imm32/alloc-id:fake
17998     _string-add/imm32/name
17999     0x11/imm32/alloc-id:fake
18000     Single-lit-var/imm32/inouts
18001     0x11/imm32/alloc-id:fake
18002     Single-int-var-in-some-register/imm32/outputs
18003     0x11/imm32/alloc-id:fake
18004     _string_81_subop_add/imm32/subx-name
18005     3/imm32/rm32-is-first-output
18006     0/imm32/no-r32
18007     1/imm32/imm32-is-first-inout
18008     0/imm32/no-imm8
18009     0/imm32/no-disp32
18010     0/imm32/output-is-write-only
18011     0x11/imm32/alloc-id:fake
18012     _Primitive-add-lit-to-mem/imm32/next
18013 _Primitive-add-lit-to-mem:  # (payload primitive)
18014     0x11/imm32/alloc-id:fake:payload
18015     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
18016     0x11/imm32/alloc-id:fake
18017     _string-add-to/imm32/name
18018     0x11/imm32/alloc-id:fake
18019     Int-var-and-literal/imm32/inouts
18020     0/imm32/no-outputs
18021     0/imm32/no-outputs
18022     0x11/imm32/alloc-id:fake
18023     _string_81_subop_add/imm32/subx-name
18024     1/imm32/rm32-is-first-inout
18025     0/imm32/no-r32
18026     2/imm32/imm32-is-second-inout
18027     0/imm32/no-imm8
18028     0/imm32/no-disp32
18029     0/imm32/output-is-write-only
18030     0x11/imm32/alloc-id:fake
18031     _Primitive-subtract-from-eax/imm32/next
18032 # - subtract
18033 _Primitive-subtract-from-eax:  # (payload primitive)
18034     0x11/imm32/alloc-id:fake:payload
18035     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
18036     0x11/imm32/alloc-id:fake
18037     _string-subtract/imm32/name
18038     0x11/imm32/alloc-id:fake
18039     Single-lit-var/imm32/inouts
18040     0x11/imm32/alloc-id:fake
18041     Single-int-var-in-eax/imm32/outputs
18042     0x11/imm32/alloc-id:fake
18043     _string_2d_subtract_from_eax/imm32/subx-name
18044     0/imm32/no-rm32
18045     0/imm32/no-r32
18046     1/imm32/imm32-is-first-inout
18047     0/imm32/no-imm8
18048     0/imm32/no-disp32
18049     0/imm32/output-is-write-only
18050     0x11/imm32/alloc-id:fake
18051     _Primitive-subtract-reg-from-reg/imm32/next
18052 _Primitive-subtract-reg-from-reg:  # (payload primitive)
18053     0x11/imm32/alloc-id:fake:payload
18054     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
18055     0x11/imm32/alloc-id:fake
18056     _string-subtract/imm32/name
18057     0x11/imm32/alloc-id:fake
18058     Single-int-var-in-some-register/imm32/inouts
18059     0x11/imm32/alloc-id:fake
18060     Single-int-var-in-some-register/imm32/outputs
18061     0x11/imm32/alloc-id:fake
18062     _string_29_subtract_from/imm32/subx-name
18063     3/imm32/rm32-is-first-output
18064     1/imm32/r32-is-first-inout
18065     0/imm32/no-imm32
18066     0/imm32/no-imm8
18067     0/imm32/no-disp32
18068     0/imm32/output-is-write-only
18069     0x11/imm32/alloc-id:fake
18070     _Primitive-subtract-reg-from-mem/imm32/next
18071 _Primitive-subtract-reg-from-mem:  # (payload primitive)
18072     0x11/imm32/alloc-id:fake:payload
18073     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
18074     0x11/imm32/alloc-id:fake
18075     _string-subtract-from/imm32/name
18076     0x11/imm32/alloc-id:fake
18077     Two-args-int-stack-int-reg/imm32/inouts
18078     0/imm32/no-outputs
18079     0/imm32/no-outputs
18080     0x11/imm32/alloc-id:fake
18081     _string_29_subtract_from/imm32/subx-name
18082     1/imm32/rm32-is-first-inout
18083     2/imm32/r32-is-second-inout
18084     0/imm32/no-imm32
18085     0/imm32/no-imm8
18086     0/imm32/no-disp32
18087     0/imm32/output-is-write-only
18088     0x11/imm32/alloc-id:fake
18089     _Primitive-subtract-mem-from-reg/imm32/next
18090 _Primitive-subtract-mem-from-reg:  # (payload primitive)
18091     0x11/imm32/alloc-id:fake:payload
18092     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
18093     0x11/imm32/alloc-id:fake
18094     _string-subtract/imm32/name
18095     0x11/imm32/alloc-id:fake
18096     Single-int-var-in-mem/imm32/inouts
18097     0x11/imm32/alloc-id:fake
18098     Single-int-var-in-some-register/imm32/outputs
18099     0x11/imm32/alloc-id:fake
18100     _string_2b_subtract/imm32/subx-name
18101     1/imm32/rm32-is-first-inout
18102     3/imm32/r32-is-first-output
18103     0/imm32/no-imm32
18104     0/imm32/no-imm8
18105     0/imm32/no-disp32
18106     0/imm32/output-is-write-only
18107     0x11/imm32/alloc-id:fake
18108     _Primitive-subtract-lit-from-reg/imm32/next
18109 _Primitive-subtract-lit-from-reg:  # (payload primitive)
18110     0x11/imm32/alloc-id:fake:payload
18111     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
18112     0x11/imm32/alloc-id:fake
18113     _string-subtract/imm32/name
18114     0x11/imm32/alloc-id:fake
18115     Single-lit-var/imm32/inouts
18116     0x11/imm32/alloc-id:fake
18117     Single-int-var-in-some-register/imm32/outputs
18118     0x11/imm32/alloc-id:fake
18119     _string_81_subop_subtract/imm32/subx-name
18120     3/imm32/rm32-is-first-output
18121     0/imm32/no-r32
18122     1/imm32/imm32-is-first-inout
18123     0/imm32/no-imm8
18124     0/imm32/no-disp32
18125     0/imm32/output-is-write-only
18126     0x11/imm32/alloc-id:fake
18127     _Primitive-subtract-lit-from-mem/imm32/next
18128 _Primitive-subtract-lit-from-mem:  # (payload primitive)
18129     0x11/imm32/alloc-id:fake:payload
18130     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
18131     0x11/imm32/alloc-id:fake
18132     _string-subtract-from/imm32/name
18133     0x11/imm32/alloc-id:fake
18134     Int-var-and-literal/imm32/inouts
18135     0/imm32/no-outputs
18136     0/imm32/no-outputs
18137     0x11/imm32/alloc-id:fake
18138     _string_81_subop_subtract/imm32/subx-name
18139     1/imm32/rm32-is-first-inout
18140     0/imm32/no-r32
18141     2/imm32/imm32-is-second-inout
18142     0/imm32/no-imm8
18143     0/imm32/no-disp32
18144     0/imm32/output-is-write-only
18145     0x11/imm32/alloc-id:fake
18146     _Primitive-and-with-eax/imm32/next
18147 # - and
18148 _Primitive-and-with-eax:  # (payload primitive)
18149     0x11/imm32/alloc-id:fake:payload
18150     # var/eax <- and lit => 25/and-with-eax lit/imm32
18151     0x11/imm32/alloc-id:fake
18152     _string-and/imm32/name
18153     0x11/imm32/alloc-id:fake
18154     Single-lit-var/imm32/inouts
18155     0x11/imm32/alloc-id:fake
18156     Single-int-var-in-eax/imm32/outputs
18157     0x11/imm32/alloc-id:fake
18158     _string_25_and_with_eax/imm32/subx-name
18159     0/imm32/no-rm32
18160     0/imm32/no-r32
18161     1/imm32/imm32-is-first-inout
18162     0/imm32/no-imm8
18163     0/imm32/no-disp32
18164     0/imm32/output-is-write-only
18165     0x11/imm32/alloc-id:fake
18166     _Primitive-and-reg-with-reg/imm32/next
18167 _Primitive-and-reg-with-reg:  # (payload primitive)
18168     0x11/imm32/alloc-id:fake:payload
18169     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
18170     0x11/imm32/alloc-id:fake
18171     _string-and/imm32/name
18172     0x11/imm32/alloc-id:fake
18173     Single-int-var-in-some-register/imm32/inouts
18174     0x11/imm32/alloc-id:fake
18175     Single-int-var-in-some-register/imm32/outputs
18176     0x11/imm32/alloc-id:fake
18177     _string_21_and_with/imm32/subx-name
18178     3/imm32/rm32-is-first-output
18179     1/imm32/r32-is-first-inout
18180     0/imm32/no-imm32
18181     0/imm32/no-imm8
18182     0/imm32/no-disp32
18183     0/imm32/output-is-write-only
18184     0x11/imm32/alloc-id:fake
18185     _Primitive-and-reg-with-mem/imm32/next
18186 _Primitive-and-reg-with-mem:  # (payload primitive)
18187     0x11/imm32/alloc-id:fake:payload
18188     # and-with var1 var2/reg => 21/and-with var1 var2/r32
18189     0x11/imm32/alloc-id:fake
18190     _string-and-with/imm32/name
18191     0x11/imm32/alloc-id:fake
18192     Two-args-int-stack-int-reg/imm32/inouts
18193     0/imm32/no-outputs
18194     0/imm32/no-outputs
18195     0x11/imm32/alloc-id:fake
18196     _string_21_and_with/imm32/subx-name
18197     1/imm32/rm32-is-first-inout
18198     2/imm32/r32-is-second-inout
18199     0/imm32/no-imm32
18200     0/imm32/no-imm8
18201     0/imm32/no-disp32
18202     0/imm32/output-is-write-only
18203     0x11/imm32/alloc-id:fake
18204     _Primitive-and-mem-with-reg/imm32/next
18205 _Primitive-and-mem-with-reg:  # (payload primitive)
18206     0x11/imm32/alloc-id:fake:payload
18207     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
18208     0x11/imm32/alloc-id:fake
18209     _string-and/imm32/name
18210     0x11/imm32/alloc-id:fake
18211     Single-int-var-in-mem/imm32/inouts
18212     0x11/imm32/alloc-id:fake
18213     Single-int-var-in-some-register/imm32/outputs
18214     0x11/imm32/alloc-id:fake
18215     _string_23_and/imm32/subx-name
18216     1/imm32/rm32-is-first-inout
18217     3/imm32/r32-is-first-output
18218     0/imm32/no-imm32
18219     0/imm32/no-imm8
18220     0/imm32/no-disp32
18221     0/imm32/output-is-write-only
18222     0x11/imm32/alloc-id:fake
18223     _Primitive-and-lit-with-reg/imm32/next
18224 _Primitive-and-lit-with-reg:  # (payload primitive)
18225     0x11/imm32/alloc-id:fake:payload
18226     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
18227     0x11/imm32/alloc-id:fake
18228     _string-and/imm32/name
18229     0x11/imm32/alloc-id:fake
18230     Single-lit-var/imm32/inouts
18231     0x11/imm32/alloc-id:fake
18232     Single-int-var-in-some-register/imm32/outputs
18233     0x11/imm32/alloc-id:fake
18234     _string_81_subop_and/imm32/subx-name
18235     3/imm32/rm32-is-first-output
18236     0/imm32/no-r32
18237     1/imm32/imm32-is-first-inout
18238     0/imm32/no-imm8
18239     0/imm32/no-disp32
18240     0/imm32/output-is-write-only
18241     0x11/imm32/alloc-id:fake
18242     _Primitive-and-lit-with-mem/imm32/next
18243 _Primitive-and-lit-with-mem:  # (payload primitive)
18244     0x11/imm32/alloc-id:fake:payload
18245     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
18246     0x11/imm32/alloc-id:fake
18247     _string-and-with/imm32/name
18248     0x11/imm32/alloc-id:fake
18249     Int-var-and-literal/imm32/inouts
18250     0/imm32/no-outputs
18251     0/imm32/no-outputs
18252     0x11/imm32/alloc-id:fake
18253     _string_81_subop_and/imm32/subx-name
18254     1/imm32/rm32-is-first-inout
18255     0/imm32/no-r32
18256     2/imm32/imm32-is-second-inout
18257     0/imm32/no-imm8
18258     0/imm32/no-disp32
18259     0/imm32/output-is-write-only
18260     0x11/imm32/alloc-id:fake
18261     _Primitive-or-with-eax/imm32/next
18262 # - or
18263 _Primitive-or-with-eax:  # (payload primitive)
18264     0x11/imm32/alloc-id:fake:payload
18265     # var/eax <- or lit => 0d/or-with-eax lit/imm32
18266     0x11/imm32/alloc-id:fake
18267     _string-or/imm32/name
18268     0x11/imm32/alloc-id:fake
18269     Single-lit-var/imm32/inouts
18270     0x11/imm32/alloc-id:fake
18271     Single-int-var-in-eax/imm32/outputs
18272     0x11/imm32/alloc-id:fake
18273     _string_0d_or_with_eax/imm32/subx-name
18274     0/imm32/no-rm32
18275     0/imm32/no-r32
18276     1/imm32/imm32-is-first-inout
18277     0/imm32/no-imm8
18278     0/imm32/no-disp32
18279     0/imm32/output-is-write-only
18280     0x11/imm32/alloc-id:fake
18281     _Primitive-or-reg-with-reg/imm32/next
18282 _Primitive-or-reg-with-reg:  # (payload primitive)
18283     0x11/imm32/alloc-id:fake:payload
18284     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
18285     0x11/imm32/alloc-id:fake
18286     _string-or/imm32/name
18287     0x11/imm32/alloc-id:fake
18288     Single-int-var-in-some-register/imm32/inouts
18289     0x11/imm32/alloc-id:fake
18290     Single-int-var-in-some-register/imm32/outputs
18291     0x11/imm32/alloc-id:fake
18292     _string_09_or_with/imm32/subx-name
18293     3/imm32/rm32-is-first-output
18294     1/imm32/r32-is-first-inout
18295     0/imm32/no-imm32
18296     0/imm32/no-imm8
18297     0/imm32/no-disp32
18298     0/imm32/output-is-write-only
18299     0x11/imm32/alloc-id:fake
18300     _Primitive-or-reg-with-mem/imm32/next
18301 _Primitive-or-reg-with-mem:  # (payload primitive)
18302     0x11/imm32/alloc-id:fake:payload
18303     # or-with var1 var2/reg => 09/or-with var1 var2/r32
18304     0x11/imm32/alloc-id:fake
18305     _string-or-with/imm32/name
18306     0x11/imm32/alloc-id:fake
18307     Two-args-int-stack-int-reg/imm32/inouts
18308     0/imm32/no-outputs
18309     0/imm32/no-outputs
18310     0x11/imm32/alloc-id:fake
18311     _string_09_or_with/imm32/subx-name
18312     1/imm32/rm32-is-first-inout
18313     2/imm32/r32-is-second-inout
18314     0/imm32/no-imm32
18315     0/imm32/no-imm8
18316     0/imm32/no-disp32
18317     0/imm32/output-is-write-only
18318     0x11/imm32/alloc-id:fake
18319     _Primitive-or-mem-with-reg/imm32/next
18320 _Primitive-or-mem-with-reg:  # (payload primitive)
18321     0x11/imm32/alloc-id:fake:payload
18322     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
18323     0x11/imm32/alloc-id:fake
18324     _string-or/imm32/name
18325     0x11/imm32/alloc-id:fake
18326     Single-int-var-in-mem/imm32/inouts
18327     0x11/imm32/alloc-id:fake
18328     Single-int-var-in-some-register/imm32/outputs
18329     0x11/imm32/alloc-id:fake
18330     _string_0b_or/imm32/subx-name
18331     1/imm32/rm32-is-first-inout
18332     3/imm32/r32-is-first-output
18333     0/imm32/no-imm32
18334     0/imm32/no-imm8
18335     0/imm32/no-disp32
18336     0/imm32/output-is-write-only
18337     0x11/imm32/alloc-id:fake
18338     _Primitive-or-lit-with-reg/imm32/next
18339 _Primitive-or-lit-with-reg:  # (payload primitive)
18340     0x11/imm32/alloc-id:fake:payload
18341     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
18342     0x11/imm32/alloc-id:fake
18343     _string-or/imm32/name
18344     0x11/imm32/alloc-id:fake
18345     Single-lit-var/imm32/inouts
18346     0x11/imm32/alloc-id:fake
18347     Single-int-var-in-some-register/imm32/outputs
18348     0x11/imm32/alloc-id:fake
18349     _string_81_subop_or/imm32/subx-name
18350     3/imm32/rm32-is-first-output
18351     0/imm32/no-r32
18352     1/imm32/imm32-is-first-inout
18353     0/imm32/no-imm8
18354     0/imm32/no-disp32
18355     0/imm32/output-is-write-only
18356     0x11/imm32/alloc-id:fake
18357     _Primitive-or-lit-with-mem/imm32/next
18358 _Primitive-or-lit-with-mem:  # (payload primitive)
18359     0x11/imm32/alloc-id:fake:payload
18360     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
18361     0x11/imm32/alloc-id:fake
18362     _string-or-with/imm32/name
18363     0x11/imm32/alloc-id:fake
18364     Int-var-and-literal/imm32/inouts
18365     0/imm32/no-outputs
18366     0/imm32/no-outputs
18367     0x11/imm32/alloc-id:fake
18368     _string_81_subop_or/imm32/subx-name
18369     1/imm32/rm32-is-first-inout
18370     0/imm32/no-r32
18371     2/imm32/imm32-is-second-inout
18372     0/imm32/no-imm8
18373     0/imm32/no-disp32
18374     0/imm32/output-is-write-only
18375     0x11/imm32/alloc-id:fake
18376     _Primitive-xor-with-eax/imm32/next
18377 # - xor
18378 _Primitive-xor-with-eax:  # (payload primitive)
18379     0x11/imm32/alloc-id:fake:payload
18380     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
18381     0x11/imm32/alloc-id:fake
18382     _string-xor/imm32/name
18383     0x11/imm32/alloc-id:fake
18384     Single-lit-var/imm32/inouts
18385     0x11/imm32/alloc-id:fake
18386     Single-int-var-in-eax/imm32/outputs
18387     0x11/imm32/alloc-id:fake
18388     _string_35_xor_with_eax/imm32/subx-name
18389     0/imm32/no-rm32
18390     0/imm32/no-r32
18391     1/imm32/imm32-is-first-inout
18392     0/imm32/no-imm8
18393     0/imm32/no-disp32
18394     0/imm32/output-is-write-only
18395     0x11/imm32/alloc-id:fake
18396     _Primitive-xor-reg-with-reg/imm32/next
18397 _Primitive-xor-reg-with-reg:  # (payload primitive)
18398     0x11/imm32/alloc-id:fake:payload
18399     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
18400     0x11/imm32/alloc-id:fake
18401     _string-xor/imm32/name
18402     0x11/imm32/alloc-id:fake
18403     Single-int-var-in-some-register/imm32/inouts
18404     0x11/imm32/alloc-id:fake
18405     Single-int-var-in-some-register/imm32/outputs
18406     0x11/imm32/alloc-id:fake
18407     _string_31_xor_with/imm32/subx-name
18408     3/imm32/rm32-is-first-output
18409     1/imm32/r32-is-first-inout
18410     0/imm32/no-imm32
18411     0/imm32/no-imm8
18412     0/imm32/no-disp32
18413     0/imm32/output-is-write-only
18414     0x11/imm32/alloc-id:fake
18415     _Primitive-xor-reg-with-mem/imm32/next
18416 _Primitive-xor-reg-with-mem:  # (payload primitive)
18417     0x11/imm32/alloc-id:fake:payload
18418     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
18419     0x11/imm32/alloc-id:fake
18420     _string-xor-with/imm32/name
18421     0x11/imm32/alloc-id:fake
18422     Two-args-int-stack-int-reg/imm32/inouts
18423     0/imm32/no-outputs
18424     0/imm32/no-outputs
18425     0x11/imm32/alloc-id:fake
18426     _string_31_xor_with/imm32/subx-name
18427     1/imm32/rm32-is-first-inout
18428     2/imm32/r32-is-second-inout
18429     0/imm32/no-imm32
18430     0/imm32/no-imm8
18431     0/imm32/no-disp32
18432     0/imm32/output-is-write-only
18433     0x11/imm32/alloc-id:fake
18434     _Primitive-xor-mem-with-reg/imm32/next
18435 _Primitive-xor-mem-with-reg:  # (payload primitive)
18436     0x11/imm32/alloc-id:fake:payload
18437     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
18438     0x11/imm32/alloc-id:fake
18439     _string-xor/imm32/name
18440     0x11/imm32/alloc-id:fake
18441     Single-int-var-in-mem/imm32/inouts
18442     0x11/imm32/alloc-id:fake
18443     Single-int-var-in-some-register/imm32/outputs
18444     0x11/imm32/alloc-id:fake
18445     _string_33_xor/imm32/subx-name
18446     1/imm32/rm32-is-first-inout
18447     3/imm32/r32-is-first-output
18448     0/imm32/no-imm32
18449     0/imm32/no-imm8
18450     0/imm32/no-disp32
18451     0/imm32/output-is-write-only
18452     0x11/imm32/alloc-id:fake
18453     _Primitive-xor-lit-with-reg/imm32/next
18454 _Primitive-xor-lit-with-reg:  # (payload primitive)
18455     0x11/imm32/alloc-id:fake:payload
18456     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
18457     0x11/imm32/alloc-id:fake
18458     _string-xor/imm32/name
18459     0x11/imm32/alloc-id:fake
18460     Single-lit-var/imm32/inouts
18461     0x11/imm32/alloc-id:fake
18462     Single-int-var-in-some-register/imm32/outputs
18463     0x11/imm32/alloc-id:fake
18464     _string_81_subop_xor/imm32/subx-name
18465     3/imm32/rm32-is-first-output
18466     0/imm32/no-r32
18467     1/imm32/imm32-is-first-inout
18468     0/imm32/no-imm8
18469     0/imm32/no-disp32
18470     0/imm32/output-is-write-only
18471     0x11/imm32/alloc-id:fake
18472     _Primitive-xor-lit-with-mem/imm32/next
18473 _Primitive-xor-lit-with-mem:  # (payload primitive)
18474     0x11/imm32/alloc-id:fake:payload
18475     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
18476     0x11/imm32/alloc-id:fake
18477     _string-xor-with/imm32/name
18478     0x11/imm32/alloc-id:fake
18479     Int-var-and-literal/imm32/inouts
18480     0/imm32/no-outputs
18481     0/imm32/no-outputs
18482     0x11/imm32/alloc-id:fake
18483     _string_81_subop_xor/imm32/subx-name
18484     1/imm32/rm32-is-first-inout
18485     0/imm32/no-r32
18486     2/imm32/imm32-is-second-inout
18487     0/imm32/no-imm8
18488     0/imm32/no-disp32
18489     0/imm32/output-is-write-only
18490     0x11/imm32/alloc-id:fake
18491     _Primitive-shift-reg-left-by-lit/imm32/next
18492 _Primitive-shift-reg-left-by-lit:  # (payload primitive)
18493     0x11/imm32/alloc-id:fake:payload
18494     # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18495     0x11/imm32/alloc-id:fake
18496     _string-shift-left/imm32/name
18497     0x11/imm32/alloc-id:fake
18498     Single-lit-var/imm32/inouts
18499     0x11/imm32/alloc-id:fake
18500     Single-int-var-in-some-register/imm32/outputs
18501     0x11/imm32/alloc-id:fake
18502     _string_c1_subop_shift_left/imm32/subx-name
18503     3/imm32/rm32-is-first-output
18504     0/imm32/no-r32
18505     0/imm32/no-imm32
18506     1/imm32/imm8-is-first-inout
18507     0/imm32/no-disp32
18508     0/imm32/output-is-write-only
18509     0x11/imm32/alloc-id:fake
18510     _Primitive-shift-reg-right-by-lit/imm32/next
18511 _Primitive-shift-reg-right-by-lit:  # (payload primitive)
18512     0x11/imm32/alloc-id:fake:payload
18513     # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18514     0x11/imm32/alloc-id:fake
18515     _string-shift-right/imm32/name
18516     0x11/imm32/alloc-id:fake
18517     Single-lit-var/imm32/inouts
18518     0x11/imm32/alloc-id:fake
18519     Single-int-var-in-some-register/imm32/outputs
18520     0x11/imm32/alloc-id:fake
18521     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18522     3/imm32/rm32-is-first-output
18523     0/imm32/no-r32
18524     0/imm32/no-imm32
18525     1/imm32/imm8-is-first-inout
18526     0/imm32/no-disp32
18527     0/imm32/output-is-write-only
18528     0x11/imm32/alloc-id:fake
18529     _Primitive-shift-reg-right-signed-by-lit/imm32/next
18530 _Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
18531     0x11/imm32/alloc-id:fake:payload
18532     # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18533     0x11/imm32/alloc-id:fake
18534     _string-shift-right-signed/imm32/name
18535     0x11/imm32/alloc-id:fake
18536     Single-lit-var/imm32/inouts
18537     0x11/imm32/alloc-id:fake
18538     Single-int-var-in-some-register/imm32/outputs
18539     0x11/imm32/alloc-id:fake
18540     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18541     3/imm32/rm32-is-first-output
18542     0/imm32/no-r32
18543     0/imm32/no-imm32
18544     1/imm32/imm8-is-first-inout
18545     0/imm32/no-disp32
18546     0/imm32/output-is-write-only
18547     0x11/imm32/alloc-id:fake
18548     _Primitive-shift-mem-left-by-lit/imm32/next
18549 _Primitive-shift-mem-left-by-lit:  # (payload primitive)
18550     0x11/imm32/alloc-id:fake:payload
18551     # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
18552     0x11/imm32/alloc-id:fake
18553     _string-shift-left/imm32/name
18554     0x11/imm32/alloc-id:fake
18555     Int-var-and-literal/imm32/inouts
18556     0/imm32/no-outputs
18557     0/imm32/no-outputs
18558     0x11/imm32/alloc-id:fake
18559     _string_c1_subop_shift_left/imm32/subx-name
18560     1/imm32/rm32-is-first-inout
18561     0/imm32/no-r32
18562     0/imm32/no-imm32
18563     2/imm32/imm8-is-second-inout
18564     0/imm32/no-disp32
18565     0/imm32/output-is-write-only
18566     0x11/imm32/alloc-id:fake
18567     _Primitive-shift-mem-right-by-lit/imm32/next
18568 _Primitive-shift-mem-right-by-lit:  # (payload primitive)
18569     0x11/imm32/alloc-id:fake:payload
18570     # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
18571     0x11/imm32/alloc-id:fake
18572     _string-shift-right/imm32/name
18573     0x11/imm32/alloc-id:fake
18574     Int-var-and-literal/imm32/inouts
18575     0/imm32/no-outputs
18576     0/imm32/no-outputs
18577     0x11/imm32/alloc-id:fake
18578     _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
18579     1/imm32/rm32-is-first-inout
18580     0/imm32/no-r32
18581     0/imm32/no-imm32
18582     2/imm32/imm8-is-second-inout
18583     0/imm32/no-disp32
18584     0/imm32/output-is-write-only
18585     0x11/imm32/alloc-id:fake
18586     _Primitive-shift-mem-right-signed-by-lit/imm32/next
18587 _Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
18588     0x11/imm32/alloc-id:fake:payload
18589     # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
18590     0x11/imm32/alloc-id:fake
18591     _string-shift-right-signed/imm32/name
18592     0x11/imm32/alloc-id:fake
18593     Int-var-and-literal/imm32/inouts
18594     0/imm32/no-outputs
18595     0/imm32/no-outputs
18596     0x11/imm32/alloc-id:fake
18597     _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
18598     1/imm32/rm32-is-first-inout
18599     0/imm32/no-r32
18600     0/imm32/no-imm32
18601     2/imm32/imm8-is-second-inout
18602     0/imm32/no-disp32
18603     0/imm32/output-is-write-only
18604     0x11/imm32/alloc-id:fake
18605     _Primitive-copy-to-eax/imm32/next
18606 # - copy
18607 _Primitive-copy-to-eax:  # (payload primitive)
18608     0x11/imm32/alloc-id:fake:payload
18609     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
18610     0x11/imm32/alloc-id:fake
18611     _string-copy/imm32/name
18612     0x11/imm32/alloc-id:fake
18613     Single-lit-var/imm32/inouts
18614     0x11/imm32/alloc-id:fake
18615     Single-int-var-in-eax/imm32/outputs
18616     0x11/imm32/alloc-id:fake
18617     _string_b8_copy_to_eax/imm32/subx-name
18618     0/imm32/no-rm32
18619     0/imm32/no-r32
18620     1/imm32/imm32-is-first-inout
18621     0/imm32/no-imm8
18622     0/imm32/no-disp32
18623     1/imm32/output-is-write-only
18624     0x11/imm32/alloc-id:fake
18625     _Primitive-copy-to-ecx/imm32/next
18626 _Primitive-copy-to-ecx:  # (payload primitive)
18627     0x11/imm32/alloc-id:fake:payload
18628     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
18629     0x11/imm32/alloc-id:fake
18630     _string-copy/imm32/name
18631     0x11/imm32/alloc-id:fake
18632     Single-lit-var/imm32/inouts
18633     0x11/imm32/alloc-id:fake
18634     Single-int-var-in-ecx/imm32/outputs
18635     0x11/imm32/alloc-id:fake
18636     _string_b9_copy_to_ecx/imm32/subx-name
18637     0/imm32/no-rm32
18638     0/imm32/no-r32
18639     1/imm32/imm32-is-first-inout
18640     0/imm32/no-imm8
18641     0/imm32/no-disp32
18642     1/imm32/output-is-write-only
18643     0x11/imm32/alloc-id:fake
18644     _Primitive-copy-to-edx/imm32/next
18645 _Primitive-copy-to-edx:  # (payload primitive)
18646     0x11/imm32/alloc-id:fake:payload
18647     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
18648     0x11/imm32/alloc-id:fake
18649     _string-copy/imm32/name
18650     0x11/imm32/alloc-id:fake
18651     Single-lit-var/imm32/inouts
18652     0x11/imm32/alloc-id:fake
18653     Single-int-var-in-edx/imm32/outputs
18654     0x11/imm32/alloc-id:fake
18655     _string_ba_copy_to_edx/imm32/subx-name
18656     0/imm32/no-rm32
18657     0/imm32/no-r32
18658     1/imm32/imm32-is-first-inout
18659     0/imm32/no-imm8
18660     0/imm32/no-disp32
18661     1/imm32/output-is-write-only
18662     0x11/imm32/alloc-id:fake
18663     _Primitive-copy-to-ebx/imm32/next
18664 _Primitive-copy-to-ebx:  # (payload primitive)
18665     0x11/imm32/alloc-id:fake:payload
18666     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
18667     0x11/imm32/alloc-id:fake
18668     _string-copy/imm32/name
18669     0x11/imm32/alloc-id:fake
18670     Single-lit-var/imm32/inouts
18671     0x11/imm32/alloc-id:fake
18672     Single-int-var-in-ebx/imm32/outputs
18673     0x11/imm32/alloc-id:fake
18674     _string_bb_copy_to_ebx/imm32/subx-name
18675     0/imm32/no-rm32
18676     0/imm32/no-r32
18677     1/imm32/imm32-is-first-inout
18678     0/imm32/no-imm8
18679     0/imm32/no-disp32
18680     1/imm32/output-is-write-only
18681     0x11/imm32/alloc-id:fake
18682     _Primitive-copy-to-esi/imm32/next
18683 _Primitive-copy-to-esi:  # (payload primitive)
18684     0x11/imm32/alloc-id:fake:payload
18685     # var/esi <- copy lit => be/copy-to-esi lit/imm32
18686     0x11/imm32/alloc-id:fake
18687     _string-copy/imm32/name
18688     0x11/imm32/alloc-id:fake
18689     Single-lit-var/imm32/inouts
18690     0x11/imm32/alloc-id:fake
18691     Single-int-var-in-esi/imm32/outputs
18692     0x11/imm32/alloc-id:fake
18693     _string_be_copy_to_esi/imm32/subx-name
18694     0/imm32/no-rm32
18695     0/imm32/no-r32
18696     1/imm32/imm32-is-first-inout
18697     0/imm32/no-imm8
18698     0/imm32/no-disp32
18699     1/imm32/output-is-write-only
18700     0x11/imm32/alloc-id:fake
18701     _Primitive-copy-to-edi/imm32/next
18702 _Primitive-copy-to-edi:  # (payload primitive)
18703     0x11/imm32/alloc-id:fake:payload
18704     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
18705     0x11/imm32/alloc-id:fake
18706     _string-copy/imm32/name
18707     0x11/imm32/alloc-id:fake
18708     Single-lit-var/imm32/inouts
18709     0x11/imm32/alloc-id:fake
18710     Single-int-var-in-edi/imm32/outputs
18711     0x11/imm32/alloc-id:fake
18712     _string_bf_copy_to_edi/imm32/subx-name
18713     0/imm32/no-rm32
18714     0/imm32/no-r32
18715     1/imm32/imm32-is-first-inout
18716     0/imm32/no-imm8
18717     0/imm32/no-disp32
18718     1/imm32/output-is-write-only
18719     0x11/imm32/alloc-id:fake
18720     _Primitive-copy-reg-to-reg/imm32/next
18721 _Primitive-copy-reg-to-reg:  # (payload primitive)
18722     0x11/imm32/alloc-id:fake:payload
18723     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
18724     0x11/imm32/alloc-id:fake
18725     _string-copy/imm32/name
18726     0x11/imm32/alloc-id:fake
18727     Single-int-var-in-some-register/imm32/inouts
18728     0x11/imm32/alloc-id:fake
18729     Single-int-var-in-some-register/imm32/outputs
18730     0x11/imm32/alloc-id:fake
18731     _string_89_<-/imm32/subx-name
18732     3/imm32/rm32-is-first-output
18733     1/imm32/r32-is-first-inout
18734     0/imm32/no-imm32
18735     0/imm32/no-imm8
18736     0/imm32/no-disp32
18737     1/imm32/output-is-write-only
18738     0x11/imm32/alloc-id:fake
18739     _Primitive-copy-reg-to-mem/imm32/next
18740 _Primitive-copy-reg-to-mem:  # (payload primitive)
18741     0x11/imm32/alloc-id:fake:payload
18742     # copy-to var1 var2/reg => 89/<- var1 var2/r32
18743     0x11/imm32/alloc-id:fake
18744     _string-copy-to/imm32/name
18745     0x11/imm32/alloc-id:fake
18746     Two-args-int-stack-int-reg/imm32/inouts
18747     0/imm32/no-outputs
18748     0/imm32/no-outputs
18749     0x11/imm32/alloc-id:fake
18750     _string_89_<-/imm32/subx-name
18751     1/imm32/rm32-is-first-inout
18752     2/imm32/r32-is-second-inout
18753     0/imm32/no-imm32
18754     0/imm32/no-imm8
18755     0/imm32/no-disp32
18756     1/imm32/output-is-write-only
18757     0x11/imm32/alloc-id:fake
18758     _Primitive-copy-mem-to-reg/imm32/next
18759 _Primitive-copy-mem-to-reg:  # (payload primitive)
18760     0x11/imm32/alloc-id:fake:payload
18761     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
18762     0x11/imm32/alloc-id:fake
18763     _string-copy/imm32/name
18764     0x11/imm32/alloc-id:fake
18765     Single-int-var-in-mem/imm32/inouts
18766     0x11/imm32/alloc-id:fake
18767     Single-int-var-in-some-register/imm32/outputs
18768     0x11/imm32/alloc-id:fake
18769     _string_8b_->/imm32/subx-name
18770     1/imm32/rm32-is-first-inout
18771     3/imm32/r32-is-first-output
18772     0/imm32/no-imm32
18773     0/imm32/no-imm8
18774     0/imm32/no-disp32
18775     1/imm32/output-is-write-only
18776     0x11/imm32/alloc-id:fake
18777     _Primitive-copy-lit-to-reg/imm32/next
18778 _Primitive-copy-lit-to-reg:  # (payload primitive)
18779     0x11/imm32/alloc-id:fake:payload
18780     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
18781     0x11/imm32/alloc-id:fake
18782     _string-copy/imm32/name
18783     0x11/imm32/alloc-id:fake
18784     Single-lit-var/imm32/inouts
18785     0x11/imm32/alloc-id:fake
18786     Single-int-var-in-some-register/imm32/outputs
18787     0x11/imm32/alloc-id:fake
18788     _string_c7_subop_copy/imm32/subx-name
18789     3/imm32/rm32-is-first-output
18790     0/imm32/no-r32
18791     1/imm32/imm32-is-first-inout
18792     0/imm32/no-imm8
18793     0/imm32/no-disp32
18794     1/imm32/output-is-write-only
18795     0x11/imm32/alloc-id:fake
18796     _Primitive-copy-lit-to-mem/imm32/next
18797 _Primitive-copy-lit-to-mem:  # (payload primitive)
18798     0x11/imm32/alloc-id:fake:payload
18799     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
18800     0x11/imm32/alloc-id:fake
18801     _string-copy-to/imm32/name
18802     0x11/imm32/alloc-id:fake
18803     Int-var-and-literal/imm32/inouts
18804     0/imm32/no-outputs
18805     0/imm32/no-outputs
18806     0x11/imm32/alloc-id:fake
18807     _string_c7_subop_copy/imm32/subx-name
18808     1/imm32/rm32-is-first-inout
18809     0/imm32/no-r32
18810     2/imm32/imm32-is-second-inout
18811     0/imm32/no-imm8
18812     0/imm32/no-disp32
18813     1/imm32/output-is-write-only
18814     0x11/imm32/alloc-id:fake
18815     _Primitive-copy-byte-from-reg/imm32/next
18816 # - copy byte
18817 _Primitive-copy-byte-from-reg:
18818     0x11/imm32/alloc-id:fake:payload
18819     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
18820     0x11/imm32/alloc-id:fake
18821     _string-copy-byte/imm32/name
18822     0x11/imm32/alloc-id:fake
18823     Single-byte-var-in-some-register/imm32/inouts
18824     0x11/imm32/alloc-id:fake
18825     Single-byte-var-in-some-register/imm32/outputs
18826     0x11/imm32/alloc-id:fake
18827     _string_8a_copy_byte/imm32/subx-name
18828     1/imm32/rm32-is-first-inout
18829     3/imm32/r32-is-first-output
18830     0/imm32/no-imm32
18831     0/imm32/no-imm8
18832     0/imm32/no-disp32
18833     1/imm32/output-is-write-only
18834     0x11/imm32/alloc-id:fake
18835     _Primitive-copy-byte-from-mem/imm32/next
18836 _Primitive-copy-byte-from-mem:
18837     0x11/imm32/alloc-id:fake:payload
18838     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
18839     0x11/imm32/alloc-id:fake
18840     _string-copy-byte/imm32/name
18841     0x11/imm32/alloc-id:fake
18842     Single-byte-var-in-mem/imm32/inouts
18843     0x11/imm32/alloc-id:fake
18844     Single-byte-var-in-some-register/imm32/outputs
18845     0x11/imm32/alloc-id:fake
18846     _string_8a_copy_byte/imm32/subx-name
18847     1/imm32/rm32-is-first-inout
18848     3/imm32/r32-is-first-output
18849     0/imm32/no-imm32
18850     0/imm32/no-imm8
18851     0/imm32/no-disp32
18852     1/imm32/output-is-write-only
18853     0x11/imm32/alloc-id:fake
18854     _Primitive-copy-byte-to-mem/imm32/next
18855 _Primitive-copy-byte-to-mem:
18856     0x11/imm32/alloc-id:fake:payload
18857     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
18858     0x11/imm32/alloc-id:fake
18859     _string-copy-byte-to/imm32/name
18860     0x11/imm32/alloc-id:fake
18861     Two-args-byte-stack-byte-reg/imm32/inouts
18862     0/imm32/no-outputs
18863     0/imm32/no-outputs
18864     0x11/imm32/alloc-id:fake
18865     _string_88_copy_byte/imm32/subx-name
18866     1/imm32/rm32-is-first-inout
18867     2/imm32/r32-is-second-inout
18868     0/imm32/no-imm32
18869     0/imm32/no-imm8
18870     0/imm32/no-disp32
18871     0/imm32/output-is-write-only
18872     0x11/imm32/alloc-id:fake
18873     _Primitive-address/imm32/next
18874 # - address
18875 _Primitive-address:  # (payload primitive)
18876     0x11/imm32/alloc-id:fake:payload
18877     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
18878     0x11/imm32/alloc-id:fake
18879     _string-address/imm32/name
18880     0x11/imm32/alloc-id:fake
18881     Single-int-var-in-mem/imm32/inouts
18882     0x11/imm32/alloc-id:fake
18883     Single-addr-var-in-some-register/imm32/outputs
18884     0x11/imm32/alloc-id:fake
18885     _string_8d_copy_address/imm32/subx-name
18886     1/imm32/rm32-is-first-inout
18887     3/imm32/r32-is-first-output
18888     0/imm32/no-imm32
18889     0/imm32/no-imm8
18890     0/imm32/no-disp32
18891     1/imm32/output-is-write-only
18892     0x11/imm32/alloc-id:fake
18893     _Primitive-compare-reg-with-reg/imm32/next
18894 # - compare
18895 _Primitive-compare-reg-with-reg:  # (payload primitive)
18896     0x11/imm32/alloc-id:fake:payload
18897     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
18898     0x11/imm32/alloc-id:fake
18899     _string-compare/imm32/name
18900     0x11/imm32/alloc-id:fake
18901     Two-int-args-in-regs/imm32/inouts
18902     0/imm32/no-outputs
18903     0/imm32/no-outputs
18904     0x11/imm32/alloc-id:fake
18905     _string_39_compare->/imm32/subx-name
18906     1/imm32/rm32-is-first-inout
18907     2/imm32/r32-is-second-inout
18908     0/imm32/no-imm32
18909     0/imm32/no-imm8
18910     0/imm32/no-disp32
18911     0/imm32/output-is-write-only
18912     0x11/imm32/alloc-id:fake
18913     _Primitive-compare-mem-with-reg/imm32/next
18914 _Primitive-compare-mem-with-reg:  # (payload primitive)
18915     0x11/imm32/alloc-id:fake:payload
18916     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
18917     0x11/imm32/alloc-id:fake
18918     _string-compare/imm32/name
18919     0x11/imm32/alloc-id:fake
18920     Two-args-int-stack-int-reg/imm32/inouts
18921     0/imm32/no-outputs
18922     0/imm32/no-outputs
18923     0x11/imm32/alloc-id:fake
18924     _string_39_compare->/imm32/subx-name
18925     1/imm32/rm32-is-first-inout
18926     2/imm32/r32-is-second-inout
18927     0/imm32/no-imm32
18928     0/imm32/no-imm8
18929     0/imm32/no-disp32
18930     0/imm32/output-is-write-only
18931     0x11/imm32/alloc-id:fake
18932     _Primitive-compare-reg-with-mem/imm32/next
18933 _Primitive-compare-reg-with-mem:  # (payload primitive)
18934     0x11/imm32/alloc-id:fake:payload
18935     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
18936     0x11/imm32/alloc-id:fake
18937     _string-compare/imm32/name
18938     0x11/imm32/alloc-id:fake
18939     Two-args-int-reg-int-stack/imm32/inouts
18940     0/imm32/no-outputs
18941     0/imm32/no-outputs
18942     0x11/imm32/alloc-id:fake
18943     _string_3b_compare<-/imm32/subx-name
18944     2/imm32/rm32-is-second-inout
18945     1/imm32/r32-is-first-inout
18946     0/imm32/no-imm32
18947     0/imm32/no-imm8
18948     0/imm32/no-disp32
18949     0/imm32/output-is-write-only
18950     0x11/imm32/alloc-id:fake
18951     _Primitive-compare-eax-with-literal/imm32/next
18952 _Primitive-compare-eax-with-literal:  # (payload primitive)
18953     0x11/imm32/alloc-id:fake:payload
18954     # compare var1/eax n => 3d/compare-eax-with n/imm32
18955     0x11/imm32/alloc-id:fake
18956     _string-compare/imm32/name
18957     0x11/imm32/alloc-id:fake
18958     Two-args-int-eax-int-literal/imm32/inouts
18959     0/imm32/no-outputs
18960     0/imm32/no-outputs
18961     0x11/imm32/alloc-id:fake
18962     _string_3d_compare_eax_with/imm32/subx-name
18963     0/imm32/no-rm32
18964     0/imm32/no-r32
18965     2/imm32/imm32-is-second-inout
18966     0/imm32/no-imm8
18967     0/imm32/no-disp32
18968     0/imm32/output-is-write-only
18969     0x11/imm32/alloc-id:fake
18970     _Primitive-compare-reg-with-literal/imm32/next
18971 _Primitive-compare-reg-with-literal:  # (payload primitive)
18972     0x11/imm32/alloc-id:fake:payload
18973     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
18974     0x11/imm32/alloc-id:fake
18975     _string-compare/imm32/name
18976     0x11/imm32/alloc-id:fake
18977     Int-var-in-register-and-literal/imm32/inouts
18978     0/imm32/no-outputs
18979     0/imm32/no-outputs
18980     0x11/imm32/alloc-id:fake
18981     _string_81_subop_compare/imm32/subx-name
18982     1/imm32/rm32-is-first-inout
18983     0/imm32/no-r32
18984     2/imm32/imm32-is-second-inout
18985     0/imm32/no-imm8
18986     0/imm32/no-disp32
18987     0/imm32/output-is-write-only
18988     0x11/imm32/alloc-id:fake
18989     _Primitive-compare-mem-with-literal/imm32/next
18990 _Primitive-compare-mem-with-literal:  # (payload primitive)
18991     0x11/imm32/alloc-id:fake:payload
18992     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
18993     0x11/imm32/alloc-id:fake
18994     _string-compare/imm32/name
18995     0x11/imm32/alloc-id:fake
18996     Int-var-and-literal/imm32/inouts
18997     0/imm32/no-outputs
18998     0/imm32/no-outputs
18999     0x11/imm32/alloc-id:fake
19000     _string_81_subop_compare/imm32/subx-name
19001     1/imm32/rm32-is-first-inout
19002     0/imm32/no-r32
19003     2/imm32/imm32-is-second-inout
19004     0/imm32/no-imm8
19005     0/imm32/no-disp32
19006     0/imm32/output-is-write-only
19007     0x11/imm32/alloc-id:fake
19008     _Primitive-negate-reg/imm32/next
19009 # - negate
19010 _Primitive-negate-reg:  # (payload primitive)
19011     0x11/imm32/alloc-id:fake:payload
19012     # var1/reg <- negate => f7 3/subop/negate var1/rm32
19013     0x11/imm32/alloc-id:fake
19014     _string-negate/imm32/name
19015     0/imm32/no-inouts
19016     0/imm32/no-inouts
19017     0x11/imm32/alloc-id:fake
19018     Single-int-var-in-some-register/imm32/outputs
19019     0x11/imm32/alloc-id:fake
19020     _string_f7_subop_negate/imm32/subx-name
19021     3/imm32/rm32-is-first-output
19022     0/imm32/no-r32
19023     0/imm32/no-imm32
19024     0/imm32/no-imm8
19025     0/imm32/no-disp32
19026     0/imm32/output-is-write-only
19027     0x11/imm32/alloc-id:fake
19028     _Primitive-negate-mem/imm32/next
19029 _Primitive-negate-mem:  # (payload primitive)
19030     0x11/imm32/alloc-id:fake:payload
19031     # negate var1 => f7 3/subop/negate var1/rm32
19032     0x11/imm32/alloc-id:fake
19033     _string-negate/imm32/name
19034     0x11/imm32/alloc-id:fake
19035     Single-int-var-in-mem/imm32/inouts
19036     0/imm32/no-outputs
19037     0/imm32/no-outputs
19038     0x11/imm32/alloc-id:fake
19039     _string_f7_subop_negate/imm32/subx-name
19040     1/imm32/rm32-is-first-inout
19041     0/imm32/no-r32
19042     0/imm32/no-imm32
19043     0/imm32/no-imm8
19044     0/imm32/no-disp32
19045     0/imm32/output-is-write-only
19046     0x11/imm32/alloc-id:fake
19047     _Primitive-multiply-reg-by-reg/imm32/next
19048 # - multiply
19049 _Primitive-multiply-reg-by-reg:  # (payload primitive)
19050     0x11/imm32/alloc-id:fake:payload
19051     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
19052     0x11/imm32/alloc-id:fake
19053     _string-multiply/imm32/name
19054     0x11/imm32/alloc-id:fake
19055     Single-int-var-in-some-register/imm32/inouts
19056     0x11/imm32/alloc-id:fake
19057     Single-int-var-in-some-register/imm32/outputs
19058     0x11/imm32/alloc-id:fake
19059     _string_0f_af_multiply/imm32/subx-name
19060     1/imm32/rm32-is-first-inout
19061     3/imm32/r32-is-first-output
19062     0/imm32/no-imm32
19063     0/imm32/no-imm8
19064     0/imm32/no-disp32
19065     0/imm32/output-is-write-only
19066     0x11/imm32/alloc-id:fake
19067     _Primitive-multiply-reg-by-mem/imm32/next
19068 _Primitive-multiply-reg-by-mem:  # (payload primitive)
19069     0x11/imm32/alloc-id:fake:payload
19070     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
19071     0x11/imm32/alloc-id:fake
19072     _string-multiply/imm32/name
19073     0x11/imm32/alloc-id:fake
19074     Single-int-var-in-mem/imm32/inouts
19075     0x11/imm32/alloc-id:fake
19076     Single-int-var-in-some-register/imm32/outputs
19077     0x11/imm32/alloc-id:fake
19078     _string_0f_af_multiply/imm32/subx-name
19079     1/imm32/rm32-is-first-inout
19080     3/imm32/r32-is-first-output
19081     0/imm32/no-imm32
19082     0/imm32/no-imm8
19083     0/imm32/no-disp32
19084     0/imm32/output-is-write-only
19085     0x11/imm32/alloc-id:fake
19086     _Primitive-break-if-addr</imm32/next
19087 # - branches
19088 _Primitive-break-if-addr<:  # (payload primitive)
19089     0x11/imm32/alloc-id:fake:payload
19090     0x11/imm32/alloc-id:fake
19091     _string-break-if-addr</imm32/name
19092     0/imm32/no-inouts
19093     0/imm32/no-inouts
19094     0/imm32/no-outputs
19095     0/imm32/no-outputs
19096     0x11/imm32/alloc-id:fake
19097     _string_0f_82_jump_break/imm32/subx-name
19098     0/imm32/no-rm32
19099     0/imm32/no-r32
19100     0/imm32/no-imm32
19101     0/imm32/no-imm8
19102     0/imm32/no-disp32
19103     0/imm32/no-output
19104     0x11/imm32/alloc-id:fake
19105     _Primitive-break-if-addr>=/imm32/next
19106 _Primitive-break-if-addr>=:  # (payload primitive)
19107     0x11/imm32/alloc-id:fake:payload
19108     0x11/imm32/alloc-id:fake
19109     _string-break-if-addr>=/imm32/name
19110     0/imm32/no-inouts
19111     0/imm32/no-inouts
19112     0/imm32/no-outputs
19113     0/imm32/no-outputs
19114     0x11/imm32/alloc-id:fake
19115     _string_0f_83_jump_break/imm32/subx-name
19116     0/imm32/no-rm32
19117     0/imm32/no-r32
19118     0/imm32/no-imm32
19119     0/imm32/no-imm8
19120     0/imm32/no-disp32
19121     0/imm32/no-output
19122     0x11/imm32/alloc-id:fake
19123     _Primitive-break-if-=/imm32/next
19124 _Primitive-break-if-=:  # (payload primitive)
19125     0x11/imm32/alloc-id:fake:payload
19126     0x11/imm32/alloc-id:fake
19127     _string-break-if-=/imm32/name
19128     0/imm32/no-inouts
19129     0/imm32/no-inouts
19130     0/imm32/no-outputs
19131     0/imm32/no-outputs
19132     0x11/imm32/alloc-id:fake
19133     _string_0f_84_jump_break/imm32/subx-name
19134     0/imm32/no-rm32
19135     0/imm32/no-r32
19136     0/imm32/no-imm32
19137     0/imm32/no-imm8
19138     0/imm32/no-disp32
19139     0/imm32/no-output
19140     0x11/imm32/alloc-id:fake
19141     _Primitive-break-if-!=/imm32/next
19142 _Primitive-break-if-!=:  # (payload primitive)
19143     0x11/imm32/alloc-id:fake:payload
19144     0x11/imm32/alloc-id:fake
19145     _string-break-if-!=/imm32/name
19146     0/imm32/no-inouts
19147     0/imm32/no-inouts
19148     0/imm32/no-outputs
19149     0/imm32/no-outputs
19150     0x11/imm32/alloc-id:fake
19151     _string_0f_85_jump_break/imm32/subx-name
19152     0/imm32/no-rm32
19153     0/imm32/no-r32
19154     0/imm32/no-imm32
19155     0/imm32/no-imm8
19156     0/imm32/no-disp32
19157     0/imm32/no-output
19158     0x11/imm32/alloc-id:fake
19159     _Primitive-break-if-addr<=/imm32/next
19160 _Primitive-break-if-addr<=:  # (payload primitive)
19161     0x11/imm32/alloc-id:fake:payload
19162     0x11/imm32/alloc-id:fake
19163     _string-break-if-addr<=/imm32/name
19164     0/imm32/no-inouts
19165     0/imm32/no-inouts
19166     0/imm32/no-outputs
19167     0/imm32/no-outputs
19168     0x11/imm32/alloc-id:fake
19169     _string_0f_86_jump_break/imm32/subx-name
19170     0/imm32/no-rm32
19171     0/imm32/no-r32
19172     0/imm32/no-imm32
19173     0/imm32/no-imm8
19174     0/imm32/no-disp32
19175     0/imm32/no-output
19176     0x11/imm32/alloc-id:fake
19177     _Primitive-break-if-addr>/imm32/next
19178 _Primitive-break-if-addr>:  # (payload primitive)
19179     0x11/imm32/alloc-id:fake:payload
19180     0x11/imm32/alloc-id:fake
19181     _string-break-if-addr>/imm32/name
19182     0/imm32/no-inouts
19183     0/imm32/no-inouts
19184     0/imm32/no-outputs
19185     0/imm32/no-outputs
19186     0x11/imm32/alloc-id:fake
19187     _string_0f_87_jump_break/imm32/subx-name
19188     0/imm32/no-rm32
19189     0/imm32/no-r32
19190     0/imm32/no-imm32
19191     0/imm32/no-imm8
19192     0/imm32/no-disp32
19193     0/imm32/no-output
19194     0x11/imm32/alloc-id:fake
19195     _Primitive-break-if-</imm32/next
19196 _Primitive-break-if-<:  # (payload primitive)
19197     0x11/imm32/alloc-id:fake:payload
19198     0x11/imm32/alloc-id:fake
19199     _string-break-if-</imm32/name
19200     0/imm32/no-inouts
19201     0/imm32/no-inouts
19202     0/imm32/no-outputs
19203     0/imm32/no-outputs
19204     0x11/imm32/alloc-id:fake
19205     _string_0f_8c_jump_break/imm32/subx-name
19206     0/imm32/no-rm32
19207     0/imm32/no-r32
19208     0/imm32/no-imm32
19209     0/imm32/no-imm8
19210     0/imm32/no-disp32
19211     0/imm32/no-output
19212     0x11/imm32/alloc-id:fake
19213     _Primitive-break-if->=/imm32/next
19214 _Primitive-break-if->=:  # (payload primitive)
19215     0x11/imm32/alloc-id:fake:payload
19216     0x11/imm32/alloc-id:fake
19217     _string-break-if->=/imm32/name
19218     0/imm32/no-inouts
19219     0/imm32/no-inouts
19220     0/imm32/no-outputs
19221     0/imm32/no-outputs
19222     0x11/imm32/alloc-id:fake
19223     _string_0f_8d_jump_break/imm32/subx-name
19224     0/imm32/no-rm32
19225     0/imm32/no-r32
19226     0/imm32/no-imm32
19227     0/imm32/no-imm8
19228     0/imm32/no-disp32
19229     0/imm32/no-output
19230     0x11/imm32/alloc-id:fake
19231     _Primitive-break-if-<=/imm32/next
19232 _Primitive-break-if-<=:  # (payload primitive)
19233     0x11/imm32/alloc-id:fake:payload
19234     0x11/imm32/alloc-id:fake
19235     _string-break-if-<=/imm32/name
19236     0/imm32/no-inouts
19237     0/imm32/no-inouts
19238     0/imm32/no-outputs
19239     0/imm32/no-outputs
19240     0x11/imm32/alloc-id:fake
19241     _string_0f_8e_jump_break/imm32/subx-name
19242     0/imm32/no-rm32
19243     0/imm32/no-r32
19244     0/imm32/no-imm32
19245     0/imm32/no-imm8
19246     0/imm32/no-disp32
19247     0/imm32/no-output
19248     0x11/imm32/alloc-id:fake
19249     _Primitive-break-if->/imm32/next
19250 _Primitive-break-if->:  # (payload primitive)
19251     0x11/imm32/alloc-id:fake:payload
19252     0x11/imm32/alloc-id:fake
19253     _string-break-if->/imm32/name
19254     0/imm32/no-inouts
19255     0/imm32/no-inouts
19256     0/imm32/no-outputs
19257     0/imm32/no-outputs
19258     0x11/imm32/alloc-id:fake
19259     _string_0f_8f_jump_break/imm32/subx-name
19260     0/imm32/no-rm32
19261     0/imm32/no-r32
19262     0/imm32/no-imm32
19263     0/imm32/no-imm8
19264     0/imm32/no-disp32
19265     0/imm32/no-output
19266     0x11/imm32/alloc-id:fake
19267     _Primitive-break/imm32/next
19268 _Primitive-break:  # (payload primitive)
19269     0x11/imm32/alloc-id:fake:payload
19270     0x11/imm32/alloc-id:fake
19271     _string-break/imm32/name
19272     0/imm32/no-inouts
19273     0/imm32/no-inouts
19274     0/imm32/no-outputs
19275     0/imm32/no-outputs
19276     0x11/imm32/alloc-id:fake
19277     _string_e9_jump_break/imm32/subx-name
19278     0/imm32/no-rm32
19279     0/imm32/no-r32
19280     0/imm32/no-imm32
19281     0/imm32/no-imm8
19282     0/imm32/no-disp32
19283     0/imm32/no-output
19284     0x11/imm32/alloc-id:fake
19285     _Primitive-loop-if-addr</imm32/next
19286 _Primitive-loop-if-addr<:  # (payload primitive)
19287     0x11/imm32/alloc-id:fake:payload
19288     0x11/imm32/alloc-id:fake
19289     _string-loop-if-addr</imm32/name
19290     0/imm32/no-inouts
19291     0/imm32/no-inouts
19292     0/imm32/no-outputs
19293     0/imm32/no-outputs
19294     0x11/imm32/alloc-id:fake
19295     _string_0f_82_jump_loop/imm32/subx-name
19296     0/imm32/no-rm32
19297     0/imm32/no-r32
19298     0/imm32/no-imm32
19299     0/imm32/no-imm8
19300     0/imm32/no-disp32
19301     0/imm32/no-output
19302     0x11/imm32/alloc-id:fake
19303     _Primitive-loop-if-addr>=/imm32/next
19304 _Primitive-loop-if-addr>=:  # (payload primitive)
19305     0x11/imm32/alloc-id:fake:payload
19306     0x11/imm32/alloc-id:fake
19307     _string-loop-if-addr>=/imm32/name
19308     0/imm32/no-inouts
19309     0/imm32/no-inouts
19310     0/imm32/no-outputs
19311     0/imm32/no-outputs
19312     0x11/imm32/alloc-id:fake
19313     _string_0f_83_jump_loop/imm32/subx-name
19314     0/imm32/no-rm32
19315     0/imm32/no-r32
19316     0/imm32/no-imm32
19317     0/imm32/no-imm8
19318     0/imm32/no-disp32
19319     0/imm32/no-output
19320     0x11/imm32/alloc-id:fake
19321     _Primitive-loop-if-=/imm32/next
19322 _Primitive-loop-if-=:  # (payload primitive)
19323     0x11/imm32/alloc-id:fake:payload
19324     0x11/imm32/alloc-id:fake
19325     _string-loop-if-=/imm32/name
19326     0/imm32/no-inouts
19327     0/imm32/no-inouts
19328     0/imm32/no-outputs
19329     0/imm32/no-outputs
19330     0x11/imm32/alloc-id:fake
19331     _string_0f_84_jump_loop/imm32/subx-name
19332     0/imm32/no-rm32
19333     0/imm32/no-r32
19334     0/imm32/no-imm32
19335     0/imm32/no-imm8
19336     0/imm32/no-disp32
19337     0/imm32/no-output
19338     0x11/imm32/alloc-id:fake
19339     _Primitive-loop-if-!=/imm32/next
19340 _Primitive-loop-if-!=:  # (payload primitive)
19341     0x11/imm32/alloc-id:fake:payload
19342     0x11/imm32/alloc-id:fake
19343     _string-loop-if-!=/imm32/name
19344     0/imm32/no-inouts
19345     0/imm32/no-inouts
19346     0/imm32/no-outputs
19347     0/imm32/no-outputs
19348     0x11/imm32/alloc-id:fake
19349     _string_0f_85_jump_loop/imm32/subx-name
19350     0/imm32/no-rm32
19351     0/imm32/no-r32
19352     0/imm32/no-imm32
19353     0/imm32/no-imm8
19354     0/imm32/no-disp32
19355     0/imm32/no-output
19356     0x11/imm32/alloc-id:fake
19357     _Primitive-loop-if-addr<=/imm32/next
19358 _Primitive-loop-if-addr<=:  # (payload primitive)
19359     0x11/imm32/alloc-id:fake:payload
19360     0x11/imm32/alloc-id:fake
19361     _string-loop-if-addr<=/imm32/name
19362     0/imm32/no-inouts
19363     0/imm32/no-inouts
19364     0/imm32/no-outputs
19365     0/imm32/no-outputs
19366     0x11/imm32/alloc-id:fake
19367     _string_0f_86_jump_loop/imm32/subx-name
19368     0/imm32/no-rm32
19369     0/imm32/no-r32
19370     0/imm32/no-imm32
19371     0/imm32/no-imm8
19372     0/imm32/no-disp32
19373     0/imm32/no-output
19374     0x11/imm32/alloc-id:fake
19375     _Primitive-loop-if-addr>/imm32/next
19376 _Primitive-loop-if-addr>:  # (payload primitive)
19377     0x11/imm32/alloc-id:fake:payload
19378     0x11/imm32/alloc-id:fake
19379     _string-loop-if-addr>/imm32/name
19380     0/imm32/no-inouts
19381     0/imm32/no-inouts
19382     0/imm32/no-outputs
19383     0/imm32/no-outputs
19384     0x11/imm32/alloc-id:fake
19385     _string_0f_87_jump_loop/imm32/subx-name
19386     0/imm32/no-rm32
19387     0/imm32/no-r32
19388     0/imm32/no-imm32
19389     0/imm32/no-imm8
19390     0/imm32/no-disp32
19391     0/imm32/no-output
19392     0x11/imm32/alloc-id:fake
19393     _Primitive-loop-if-</imm32/next
19394 _Primitive-loop-if-<:  # (payload primitive)
19395     0x11/imm32/alloc-id:fake:payload
19396     0x11/imm32/alloc-id:fake
19397     _string-loop-if-</imm32/name
19398     0/imm32/no-inouts
19399     0/imm32/no-inouts
19400     0/imm32/no-outputs
19401     0/imm32/no-outputs
19402     0x11/imm32/alloc-id:fake
19403     _string_0f_8c_jump_loop/imm32/subx-name
19404     0/imm32/no-rm32
19405     0/imm32/no-r32
19406     0/imm32/no-imm32
19407     0/imm32/no-imm8
19408     0/imm32/no-disp32
19409     0/imm32/no-output
19410     0x11/imm32/alloc-id:fake
19411     _Primitive-loop-if->=/imm32/next
19412 _Primitive-loop-if->=:  # (payload primitive)
19413     0x11/imm32/alloc-id:fake:payload
19414     0x11/imm32/alloc-id:fake
19415     _string-loop-if->=/imm32/name
19416     0/imm32/no-inouts
19417     0/imm32/no-inouts
19418     0/imm32/no-outputs
19419     0/imm32/no-outputs
19420     0x11/imm32/alloc-id:fake
19421     _string_0f_8d_jump_loop/imm32/subx-name
19422     0/imm32/no-rm32
19423     0/imm32/no-r32
19424     0/imm32/no-imm32
19425     0/imm32/no-imm8
19426     0/imm32/no-disp32
19427     0/imm32/no-output
19428     0x11/imm32/alloc-id:fake
19429     _Primitive-loop-if-<=/imm32/next
19430 _Primitive-loop-if-<=:  # (payload primitive)
19431     0x11/imm32/alloc-id:fake:payload
19432     0x11/imm32/alloc-id:fake
19433     _string-loop-if-<=/imm32/name
19434     0/imm32/no-inouts
19435     0/imm32/no-inouts
19436     0/imm32/no-outputs
19437     0/imm32/no-outputs
19438     0x11/imm32/alloc-id:fake
19439     _string_0f_8e_jump_loop/imm32/subx-name
19440     0/imm32/no-rm32
19441     0/imm32/no-r32
19442     0/imm32/no-imm32
19443     0/imm32/no-imm8
19444     0/imm32/no-disp32
19445     0/imm32/no-output
19446     0x11/imm32/alloc-id:fake
19447     _Primitive-loop-if->/imm32/next
19448 _Primitive-loop-if->:  # (payload primitive)
19449     0x11/imm32/alloc-id:fake:payload
19450     0x11/imm32/alloc-id:fake
19451     _string-loop-if->/imm32/name
19452     0/imm32/no-inouts
19453     0/imm32/no-inouts
19454     0/imm32/no-outputs
19455     0/imm32/no-outputs
19456     0x11/imm32/alloc-id:fake
19457     _string_0f_8f_jump_loop/imm32/subx-name
19458     0/imm32/no-rm32
19459     0/imm32/no-r32
19460     0/imm32/no-imm32
19461     0/imm32/no-imm8
19462     0/imm32/no-disp32
19463     0/imm32/no-output
19464     0x11/imm32/alloc-id:fake
19465     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
19466 _Primitive-loop:  # (payload primitive)
19467     0x11/imm32/alloc-id:fake:payload
19468     0x11/imm32/alloc-id:fake
19469     _string-loop/imm32/name
19470     0/imm32/no-inouts
19471     0/imm32/no-inouts
19472     0/imm32/no-outputs
19473     0/imm32/no-outputs
19474     0x11/imm32/alloc-id:fake
19475     _string_e9_jump_loop/imm32/subx-name
19476     0/imm32/no-rm32
19477     0/imm32/no-r32
19478     0/imm32/no-imm32
19479     0/imm32/no-imm8
19480     0/imm32/no-disp32
19481     0/imm32/no-output
19482     0x11/imm32/alloc-id:fake
19483     _Primitive-break-if-addr<-named/imm32/next
19484 # - branches to named blocks
19485 _Primitive-break-if-addr<-named:  # (payload primitive)
19486     0x11/imm32/alloc-id:fake:payload
19487     0x11/imm32/alloc-id:fake
19488     _string-break-if-addr</imm32/name
19489     0x11/imm32/alloc-id:fake
19490     Single-lit-var/imm32/inouts
19491     0/imm32/no-outputs
19492     0/imm32/no-outputs
19493     0x11/imm32/alloc-id:fake
19494     _string_0f_82_jump_label/imm32/subx-name
19495     0/imm32/no-rm32
19496     0/imm32/no-r32
19497     0/imm32/no-imm32
19498     0/imm32/no-imm8
19499     1/imm32/disp32-is-first-inout
19500     0/imm32/no-output
19501     0x11/imm32/alloc-id:fake
19502     _Primitive-break-if-addr>=-named/imm32/next
19503 _Primitive-break-if-addr>=-named:  # (payload primitive)
19504     0x11/imm32/alloc-id:fake:payload
19505     0x11/imm32/alloc-id:fake
19506     _string-break-if-addr>=/imm32/name
19507     0x11/imm32/alloc-id:fake
19508     Single-lit-var/imm32/inouts
19509     0/imm32/no-outputs
19510     0/imm32/no-outputs
19511     0x11/imm32/alloc-id:fake
19512     _string_0f_83_jump_label/imm32/subx-name
19513     0/imm32/no-rm32
19514     0/imm32/no-r32
19515     0/imm32/no-imm32
19516     0/imm32/no-imm8
19517     1/imm32/disp32-is-first-inout
19518     0/imm32/no-output
19519     0x11/imm32/alloc-id:fake
19520     _Primitive-break-if-=-named/imm32/next
19521 _Primitive-break-if-=-named:  # (payload primitive)
19522     0x11/imm32/alloc-id:fake:payload
19523     0x11/imm32/alloc-id:fake
19524     _string-break-if-=/imm32/name
19525     0x11/imm32/alloc-id:fake
19526     Single-lit-var/imm32/inouts
19527     0/imm32/no-outputs
19528     0/imm32/no-outputs
19529     0x11/imm32/alloc-id:fake
19530     _string_0f_84_jump_label/imm32/subx-name
19531     0/imm32/no-rm32
19532     0/imm32/no-r32
19533     0/imm32/no-imm32
19534     0/imm32/no-imm8
19535     1/imm32/disp32-is-first-inout
19536     0/imm32/no-output
19537     0x11/imm32/alloc-id:fake
19538     _Primitive-break-if-!=-named/imm32/next
19539 _Primitive-break-if-!=-named:  # (payload primitive)
19540     0x11/imm32/alloc-id:fake:payload
19541     0x11/imm32/alloc-id:fake
19542     _string-break-if-!=/imm32/name
19543     0x11/imm32/alloc-id:fake
19544     Single-lit-var/imm32/inouts
19545     0/imm32/no-outputs
19546     0/imm32/no-outputs
19547     0x11/imm32/alloc-id:fake
19548     _string_0f_85_jump_label/imm32/subx-name
19549     0/imm32/no-rm32
19550     0/imm32/no-r32
19551     0/imm32/no-imm32
19552     0/imm32/no-imm8
19553     1/imm32/disp32-is-first-inout
19554     0/imm32/no-output
19555     0x11/imm32/alloc-id:fake
19556     _Primitive-break-if-addr<=-named/imm32/next
19557 _Primitive-break-if-addr<=-named:  # (payload primitive)
19558     0x11/imm32/alloc-id:fake:payload
19559     0x11/imm32/alloc-id:fake
19560     _string-break-if-addr<=/imm32/name
19561     0x11/imm32/alloc-id:fake
19562     Single-lit-var/imm32/inouts
19563     0/imm32/no-outputs
19564     0/imm32/no-outputs
19565     0x11/imm32/alloc-id:fake
19566     _string_0f_86_jump_label/imm32/subx-name
19567     0/imm32/no-rm32
19568     0/imm32/no-r32
19569     0/imm32/no-imm32
19570     0/imm32/no-imm8
19571     1/imm32/disp32-is-first-inout
19572     0/imm32/no-output
19573     0x11/imm32/alloc-id:fake
19574     _Primitive-break-if-addr>-named/imm32/next
19575 _Primitive-break-if-addr>-named:  # (payload primitive)
19576     0x11/imm32/alloc-id:fake:payload
19577     0x11/imm32/alloc-id:fake
19578     _string-break-if-addr>/imm32/name
19579     0x11/imm32/alloc-id:fake
19580     Single-lit-var/imm32/inouts
19581     0/imm32/no-outputs
19582     0/imm32/no-outputs
19583     0x11/imm32/alloc-id:fake
19584     _string_0f_87_jump_label/imm32/subx-name
19585     0/imm32/no-rm32
19586     0/imm32/no-r32
19587     0/imm32/no-imm32
19588     0/imm32/no-imm8
19589     1/imm32/disp32-is-first-inout
19590     0/imm32/no-output
19591     0x11/imm32/alloc-id:fake
19592     _Primitive-break-if-<-named/imm32/next
19593 _Primitive-break-if-<-named:  # (payload primitive)
19594     0x11/imm32/alloc-id:fake:payload
19595     0x11/imm32/alloc-id:fake
19596     _string-break-if-</imm32/name
19597     0x11/imm32/alloc-id:fake
19598     Single-lit-var/imm32/inouts
19599     0/imm32/no-outputs
19600     0/imm32/no-outputs
19601     0x11/imm32/alloc-id:fake
19602     _string_0f_8c_jump_label/imm32/subx-name
19603     0/imm32/no-rm32
19604     0/imm32/no-r32
19605     0/imm32/no-imm32
19606     0/imm32/no-imm8
19607     1/imm32/disp32-is-first-inout
19608     0/imm32/no-output
19609     0x11/imm32/alloc-id:fake
19610     _Primitive-break-if->=-named/imm32/next
19611 _Primitive-break-if->=-named:  # (payload primitive)
19612     0x11/imm32/alloc-id:fake:payload
19613     0x11/imm32/alloc-id:fake
19614     _string-break-if->=/imm32/name
19615     0x11/imm32/alloc-id:fake
19616     Single-lit-var/imm32/inouts
19617     0/imm32/no-outputs
19618     0/imm32/no-outputs
19619     0x11/imm32/alloc-id:fake
19620     _string_0f_8d_jump_label/imm32/subx-name
19621     0/imm32/no-rm32
19622     0/imm32/no-r32
19623     0/imm32/no-imm32
19624     0/imm32/no-imm8
19625     1/imm32/disp32-is-first-inout
19626     0/imm32/no-output
19627     0x11/imm32/alloc-id:fake
19628     _Primitive-break-if-<=-named/imm32/next
19629 _Primitive-break-if-<=-named:  # (payload primitive)
19630     0x11/imm32/alloc-id:fake:payload
19631     0x11/imm32/alloc-id:fake
19632     _string-break-if-<=/imm32/name
19633     0x11/imm32/alloc-id:fake
19634     Single-lit-var/imm32/inouts
19635     0/imm32/no-outputs
19636     0/imm32/no-outputs
19637     0x11/imm32/alloc-id:fake
19638     _string_0f_8e_jump_label/imm32/subx-name
19639     0/imm32/no-rm32
19640     0/imm32/no-r32
19641     0/imm32/no-imm32
19642     0/imm32/no-imm8
19643     1/imm32/disp32-is-first-inout
19644     0/imm32/no-output
19645     0x11/imm32/alloc-id:fake
19646     _Primitive-break-if->-named/imm32/next
19647 _Primitive-break-if->-named:  # (payload primitive)
19648     0x11/imm32/alloc-id:fake:payload
19649     0x11/imm32/alloc-id:fake
19650     _string-break-if->/imm32/name
19651     0x11/imm32/alloc-id:fake
19652     Single-lit-var/imm32/inouts
19653     0/imm32/no-outputs
19654     0/imm32/no-outputs
19655     0x11/imm32/alloc-id:fake
19656     _string_0f_8f_jump_label/imm32/subx-name
19657     0/imm32/no-rm32
19658     0/imm32/no-r32
19659     0/imm32/no-imm32
19660     0/imm32/no-imm8
19661     1/imm32/disp32-is-first-inout
19662     0/imm32/no-output
19663     0x11/imm32/alloc-id:fake
19664     _Primitive-break-named/imm32/next
19665 _Primitive-break-named:  # (payload primitive)
19666     0x11/imm32/alloc-id:fake:payload
19667     0x11/imm32/alloc-id:fake
19668     _string-break/imm32/name
19669     0x11/imm32/alloc-id:fake
19670     Single-lit-var/imm32/inouts
19671     0/imm32/no-outputs
19672     0/imm32/no-outputs
19673     0x11/imm32/alloc-id:fake
19674     _string_e9_jump_label/imm32/subx-name
19675     0/imm32/no-rm32
19676     0/imm32/no-r32
19677     0/imm32/no-imm32
19678     0/imm32/no-imm8
19679     1/imm32/disp32-is-first-inout
19680     0/imm32/no-output
19681     0x11/imm32/alloc-id:fake
19682     _Primitive-loop-if-addr<-named/imm32/next
19683 _Primitive-loop-if-addr<-named:  # (payload primitive)
19684     0x11/imm32/alloc-id:fake:payload
19685     0x11/imm32/alloc-id:fake
19686     _string-loop-if-addr</imm32/name
19687     0x11/imm32/alloc-id:fake
19688     Single-lit-var/imm32/inouts
19689     0/imm32/no-outputs
19690     0/imm32/no-outputs
19691     0x11/imm32/alloc-id:fake
19692     _string_0f_82_jump_label/imm32/subx-name
19693     0/imm32/no-rm32
19694     0/imm32/no-r32
19695     0/imm32/no-imm32
19696     0/imm32/no-imm8
19697     1/imm32/disp32-is-first-inout
19698     0/imm32/no-output
19699     0x11/imm32/alloc-id:fake
19700     _Primitive-loop-if-addr>=-named/imm32/next
19701 _Primitive-loop-if-addr>=-named:  # (payload primitive)
19702     0x11/imm32/alloc-id:fake:payload
19703     0x11/imm32/alloc-id:fake
19704     _string-loop-if-addr>=/imm32/name
19705     0x11/imm32/alloc-id:fake
19706     Single-lit-var/imm32/inouts
19707     0/imm32/no-outputs
19708     0/imm32/no-outputs
19709     0x11/imm32/alloc-id:fake
19710     _string_0f_83_jump_label/imm32/subx-name
19711     0/imm32/no-rm32
19712     0/imm32/no-r32
19713     0/imm32/no-imm32
19714     0/imm32/no-imm8
19715     1/imm32/disp32-is-first-inout
19716     0/imm32/no-output
19717     0x11/imm32/alloc-id:fake
19718     _Primitive-loop-if-=-named/imm32/next
19719 _Primitive-loop-if-=-named:  # (payload primitive)
19720     0x11/imm32/alloc-id:fake:payload
19721     0x11/imm32/alloc-id:fake
19722     _string-loop-if-=/imm32/name
19723     0x11/imm32/alloc-id:fake
19724     Single-lit-var/imm32/inouts
19725     0/imm32/no-outputs
19726     0/imm32/no-outputs
19727     0x11/imm32/alloc-id:fake
19728     _string_0f_84_jump_label/imm32/subx-name
19729     0/imm32/no-rm32
19730     0/imm32/no-r32
19731     0/imm32/no-imm32
19732     0/imm32/no-imm8
19733     1/imm32/disp32-is-first-inout
19734     0/imm32/no-output
19735     0x11/imm32/alloc-id:fake
19736     _Primitive-loop-if-!=-named/imm32/next
19737 _Primitive-loop-if-!=-named:  # (payload primitive)
19738     0x11/imm32/alloc-id:fake:payload
19739     0x11/imm32/alloc-id:fake
19740     _string-loop-if-!=/imm32/name
19741     0x11/imm32/alloc-id:fake
19742     Single-lit-var/imm32/inouts
19743     0/imm32/no-outputs
19744     0/imm32/no-outputs
19745     0x11/imm32/alloc-id:fake
19746     _string_0f_85_jump_label/imm32/subx-name
19747     0/imm32/no-rm32
19748     0/imm32/no-r32
19749     0/imm32/no-imm32
19750     0/imm32/no-imm8
19751     1/imm32/disp32-is-first-inout
19752     0/imm32/no-output
19753     0x11/imm32/alloc-id:fake
19754     _Primitive-loop-if-addr<=-named/imm32/next
19755 _Primitive-loop-if-addr<=-named:  # (payload primitive)
19756     0x11/imm32/alloc-id:fake:payload
19757     0x11/imm32/alloc-id:fake
19758     _string-loop-if-addr<=/imm32/name
19759     0x11/imm32/alloc-id:fake
19760     Single-lit-var/imm32/inouts
19761     0/imm32/no-outputs
19762     0/imm32/no-outputs
19763     0x11/imm32/alloc-id:fake
19764     _string_0f_86_jump_label/imm32/subx-name
19765     0/imm32/no-rm32
19766     0/imm32/no-r32
19767     0/imm32/no-imm32
19768     0/imm32/no-imm8
19769     1/imm32/disp32-is-first-inout
19770     0/imm32/no-output
19771     0x11/imm32/alloc-id:fake
19772     _Primitive-loop-if-addr>-named/imm32/next
19773 _Primitive-loop-if-addr>-named:  # (payload primitive)
19774     0x11/imm32/alloc-id:fake:payload
19775     0x11/imm32/alloc-id:fake
19776     _string-loop-if-addr>/imm32/name
19777     0x11/imm32/alloc-id:fake
19778     Single-lit-var/imm32/inouts
19779     0/imm32/no-outputs
19780     0/imm32/no-outputs
19781     0x11/imm32/alloc-id:fake
19782     _string_0f_87_jump_label/imm32/subx-name
19783     0/imm32/no-rm32
19784     0/imm32/no-r32
19785     0/imm32/no-imm32
19786     0/imm32/no-imm8
19787     1/imm32/disp32-is-first-inout
19788     0/imm32/no-output
19789     0x11/imm32/alloc-id:fake
19790     _Primitive-loop-if-<-named/imm32/next
19791 _Primitive-loop-if-<-named:  # (payload primitive)
19792     0x11/imm32/alloc-id:fake:payload
19793     0x11/imm32/alloc-id:fake
19794     _string-loop-if-</imm32/name
19795     0x11/imm32/alloc-id:fake
19796     Single-lit-var/imm32/inouts
19797     0/imm32/no-outputs
19798     0/imm32/no-outputs
19799     0x11/imm32/alloc-id:fake
19800     _string_0f_8c_jump_label/imm32/subx-name
19801     0/imm32/no-rm32
19802     0/imm32/no-r32
19803     0/imm32/no-imm32
19804     0/imm32/no-imm8
19805     1/imm32/disp32-is-first-inout
19806     0/imm32/no-output
19807     0x11/imm32/alloc-id:fake
19808     _Primitive-loop-if->=-named/imm32/next
19809 _Primitive-loop-if->=-named:  # (payload primitive)
19810     0x11/imm32/alloc-id:fake:payload
19811     0x11/imm32/alloc-id:fake
19812     _string-loop-if->=/imm32/name
19813     0x11/imm32/alloc-id:fake
19814     Single-lit-var/imm32/inouts
19815     0/imm32/no-outputs
19816     0/imm32/no-outputs
19817     0x11/imm32/alloc-id:fake
19818     _string_0f_8d_jump_label/imm32/subx-name
19819     0/imm32/no-rm32
19820     0/imm32/no-r32
19821     0/imm32/no-imm32
19822     0/imm32/no-imm8
19823     1/imm32/disp32-is-first-inout
19824     0/imm32/no-output
19825     0x11/imm32/alloc-id:fake
19826     _Primitive-loop-if-<=-named/imm32/next
19827 _Primitive-loop-if-<=-named:  # (payload primitive)
19828     0x11/imm32/alloc-id:fake:payload
19829     0x11/imm32/alloc-id:fake
19830     _string-loop-if-<=/imm32/name
19831     0x11/imm32/alloc-id:fake
19832     Single-lit-var/imm32/inouts
19833     0/imm32/no-outputs
19834     0/imm32/no-outputs
19835     0x11/imm32/alloc-id:fake
19836     _string_0f_8e_jump_label/imm32/subx-name
19837     0/imm32/no-rm32
19838     0/imm32/no-r32
19839     0/imm32/no-imm32
19840     0/imm32/no-imm8
19841     1/imm32/disp32-is-first-inout
19842     0/imm32/no-output
19843     0x11/imm32/alloc-id:fake
19844     _Primitive-loop-if->-named/imm32/next
19845 _Primitive-loop-if->-named:  # (payload primitive)
19846     0x11/imm32/alloc-id:fake:payload
19847     0x11/imm32/alloc-id:fake
19848     _string-loop-if->/imm32/name
19849     0x11/imm32/alloc-id:fake
19850     Single-lit-var/imm32/inouts
19851     0/imm32/no-outputs
19852     0/imm32/no-outputs
19853     0x11/imm32/alloc-id:fake
19854     _string_0f_8f_jump_label/imm32/subx-name
19855     0/imm32/no-rm32
19856     0/imm32/no-r32
19857     0/imm32/no-imm32
19858     0/imm32/no-imm8
19859     1/imm32/disp32-is-first-inout
19860     0/imm32/no-output
19861     0x11/imm32/alloc-id:fake
19862     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
19863 _Primitive-loop-named:  # (payload primitive)
19864     0x11/imm32/alloc-id:fake:payload
19865     0x11/imm32/alloc-id:fake
19866     _string-loop/imm32/name
19867     0x11/imm32/alloc-id:fake
19868     Single-lit-var/imm32/inouts
19869     0/imm32/no-outputs
19870     0/imm32/no-outputs
19871     0x11/imm32/alloc-id:fake
19872     _string_e9_jump_label/imm32/subx-name
19873     0/imm32/no-rm32
19874     0/imm32/no-r32
19875     0/imm32/no-imm32
19876     0/imm32/no-imm8
19877     1/imm32/disp32-is-first-inout
19878     0/imm32/no-output
19879     0/imm32/next
19880     0/imm32/next
19881 
19882 # string literals for Mu instructions
19883 _string-add:  # (payload array byte)
19884     0x11/imm32/alloc-id:fake:payload
19885     # "add"
19886     0x3/imm32/size
19887     0x61/a 0x64/d 0x64/d
19888 _string-address:  # (payload array byte)
19889     0x11/imm32/alloc-id:fake:payload
19890     # "address"
19891     0x7/imm32/size
19892     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
19893 _string-add-to:  # (payload array byte)
19894     0x11/imm32/alloc-id:fake:payload
19895     # "add-to"
19896     0x6/imm32/size
19897     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
19898 _string-and:  # (payload array byte)
19899     0x11/imm32/alloc-id:fake:payload
19900     # "and"
19901     0x3/imm32/size
19902     0x61/a 0x6e/n 0x64/d
19903 _string-and-with:  # (payload array byte)
19904     0x11/imm32/alloc-id:fake:payload
19905     # "and-with"
19906     0x8/imm32/size
19907     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
19908 _string-break:  # (payload array byte)
19909     0x11/imm32/alloc-id:fake:payload
19910     # "break"
19911     0x5/imm32/size
19912     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
19913 _string-break-if-<:  # (payload array byte)
19914     0x11/imm32/alloc-id:fake:payload
19915     # "break-if-<"
19916     0xa/imm32/size
19917     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
19918 _string-break-if-<=:  # (payload array byte)
19919     0x11/imm32/alloc-id:fake:payload
19920     # "break-if-<="
19921     0xb/imm32/size
19922     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
19923 _string-break-if-=:  # (payload array byte)
19924     0x11/imm32/alloc-id:fake:payload
19925     # "break-if-="
19926     0xa/imm32/size
19927     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
19928 _string-break-if->:  # (payload array byte)
19929     0x11/imm32/alloc-id:fake:payload
19930     # "break-if->"
19931     0xa/imm32/size
19932     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
19933 _string-break-if->=:  # (payload array byte)
19934     0x11/imm32/alloc-id:fake:payload
19935     # "break-if->="
19936     0xb/imm32/size
19937     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
19938 _string-break-if-!=:  # (payload array byte)
19939     0x11/imm32/alloc-id:fake:payload
19940     # "break-if-!="
19941     0xb/imm32/size
19942     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
19943 _string-break-if-addr<:  # (payload array byte)
19944     0x11/imm32/alloc-id:fake:payload
19945     # "break-if-addr<"
19946     0xe/imm32/size
19947     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/<
19948 _string-break-if-addr<=:  # (payload array byte)
19949     0x11/imm32/alloc-id:fake:payload
19950     # "break-if-addr<="
19951     0xf/imm32/size
19952     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/=
19953 _string-break-if-addr>:  # (payload array byte)
19954     0x11/imm32/alloc-id:fake:payload
19955     # "break-if-addr>"
19956     0xe/imm32/size
19957     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/>
19958 _string-break-if-addr>=:  # (payload array byte)
19959     0x11/imm32/alloc-id:fake:payload
19960     # "break-if-addr>="
19961     0xf/imm32/size
19962     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/=
19963 _string-compare:  # (payload array byte)
19964     0x11/imm32/alloc-id:fake:payload
19965     # "compare"
19966     0x7/imm32/size
19967     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
19968 _string-copy:  # (payload array byte)
19969     0x11/imm32/alloc-id:fake:payload
19970     # "copy"
19971     0x4/imm32/size
19972     0x63/c 0x6f/o 0x70/p 0x79/y
19973 _string-copy-to:  # (payload array byte)
19974     0x11/imm32/alloc-id:fake:payload
19975     # "copy-to"
19976     0x7/imm32/size
19977     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
19978 _string-copy-byte:
19979     0x11/imm32/alloc-id:fake:payload
19980     # "copy-byte"
19981     0x9/imm32/size
19982     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
19983 _string-copy-byte-to:
19984     0x11/imm32/alloc-id:fake:payload
19985     # "copy-byte-to"
19986     0xc/imm32/size
19987     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
19988 _string-decrement:  # (payload array byte)
19989     0x11/imm32/alloc-id:fake:payload
19990     # "decrement"
19991     0x9/imm32/size
19992     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19993 _string-increment:  # (payload array byte)
19994     0x11/imm32/alloc-id:fake:payload
19995     # "increment"
19996     0x9/imm32/size
19997     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
19998 _string-loop:  # (payload array byte)
19999     0x11/imm32/alloc-id:fake:payload
20000     # "loop"
20001     0x4/imm32/size
20002     0x6c/l 0x6f/o 0x6f/o 0x70/p
20003 _string-loop-if-<:  # (payload array byte)
20004     0x11/imm32/alloc-id:fake:payload
20005     # "loop-if-<"
20006     0x9/imm32/size
20007     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
20008 _string-loop-if-<=:  # (payload array byte)
20009     0x11/imm32/alloc-id:fake:payload
20010     # "loop-if-<="
20011     0xa/imm32/size
20012     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
20013 _string-loop-if-=:  # (payload array byte)
20014     0x11/imm32/alloc-id:fake:payload
20015     # "loop-if-="
20016     0x9/imm32/size
20017     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
20018 _string-loop-if->:  # (payload array byte)
20019     0x11/imm32/alloc-id:fake:payload
20020     # "loop-if->"
20021     0x9/imm32/size
20022     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
20023 _string-loop-if->=:  # (payload array byte)
20024     0x11/imm32/alloc-id:fake:payload
20025     # "loop-if->="
20026     0xa/imm32/size
20027     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
20028 _string-loop-if-!=:  # (payload array byte)
20029     0x11/imm32/alloc-id:fake:payload
20030     # "loop-if-!="
20031     0xa/imm32/size
20032     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
20033 _string-loop-if-addr<:  # (payload array byte)
20034     0x11/imm32/alloc-id:fake:payload
20035     # "loop-if-addr<"
20036     0xd/imm32/size
20037     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/<
20038 _string-loop-if-addr<=:  # (payload array byte)
20039     0x11/imm32/alloc-id:fake:payload
20040     # "loop-if-addr<="
20041     0xe/imm32/size
20042     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/=
20043 _string-loop-if-addr>:  # (payload array byte)
20044     0x11/imm32/alloc-id:fake:payload
20045     # "loop-if-addr>"
20046     0xd/imm32/size
20047     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/>
20048 _string-loop-if-addr>=:  # (payload array byte)
20049     0x11/imm32/alloc-id:fake:payload
20050     # "loop-if-addr>="
20051     0xe/imm32/size
20052     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/=
20053 _string-multiply:  # (payload array byte)
20054     0x11/imm32/alloc-id:fake:payload
20055     # "multiply"
20056     0x8/imm32/size
20057     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
20058 _string-negate:  # (payload array byte)
20059     0x11/imm32/alloc-id:fake:payload
20060     # "negate"
20061     0x6/imm32/size
20062     0x6e/n 0x65/e 0x67/g 0x61/a 0x74/t 0x65/e
20063 _string-or:  # (payload array byte)
20064     0x11/imm32/alloc-id:fake:payload
20065     # "or"
20066     0x2/imm32/size
20067     0x6f/o 0x72/r
20068 _string-or-with:  # (payload array byte)
20069     0x11/imm32/alloc-id:fake:payload
20070     # "or-with"
20071     0x7/imm32/size
20072     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20073 _string-subtract:  # (payload array byte)
20074     0x11/imm32/alloc-id:fake:payload
20075     # "subtract"
20076     0x8/imm32/size
20077     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
20078 _string-subtract-from:  # (payload array byte)
20079     0x11/imm32/alloc-id:fake:payload
20080     # "subtract-from"
20081     0xd/imm32/size
20082     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
20083 _string-xor:  # (payload array byte)
20084     0x11/imm32/alloc-id:fake:payload
20085     # "xor"
20086     0x3/imm32/size
20087     0x78/x 0x6f/o 0x72/r
20088 _string-xor-with:  # (payload array byte)
20089     0x11/imm32/alloc-id:fake:payload
20090     # "xor-with"
20091     0x8/imm32/size
20092     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20093 _string-shift-left:  # (payload array byte)
20094     0x11/imm32/alloc-id:fake:payload
20095     # "shift-left"
20096     0xa/imm32/size
20097     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
20098 _string-shift-right:  # (payload array byte)
20099     0x11/imm32/alloc-id:fake:payload
20100     # "shift-right"
20101     0xb/imm32/size
20102     0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
20103 _string-shift-right-signed:  # (payload array byte)
20104     0x11/imm32/alloc-id:fake:payload
20105     # "shift-right-signed"
20106     0x12/imm32/size
20107     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
20108 
20109 # string literals for SubX instructions
20110 _string_01_add_to:  # (payload array byte)
20111     0x11/imm32/alloc-id:fake:payload
20112     # "01/add-to"
20113     0x9/imm32/size
20114     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
20115 _string_03_add:  # (payload array byte)
20116     0x11/imm32/alloc-id:fake:payload
20117     # "03/add"
20118     0x6/imm32/size
20119     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
20120 _string_05_add_to_eax:  # (payload array byte)
20121     0x11/imm32/alloc-id:fake:payload
20122     # "05/add-to-eax"
20123     0xd/imm32/size
20124     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
20125 _string_09_or_with:  # (payload array byte)
20126     0x11/imm32/alloc-id:fake:payload
20127     # "09/or-with"
20128     0xa/imm32/size
20129     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20130 _string_0b_or:  # (payload array byte)
20131     0x11/imm32/alloc-id:fake:payload
20132     # "0b/or"
20133     0x5/imm32/size
20134     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
20135 _string_0d_or_with_eax:  # (payload array byte)
20136     0x11/imm32/alloc-id:fake:payload
20137     # "0d/or-with-eax"
20138     0xe/imm32/size
20139     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
20140 _string_0f_82_jump_label:  # (payload array byte)
20141     0x11/imm32/alloc-id:fake:payload
20142     # "0f 82/jump-if-addr<"
20143     0x13/imm32/size
20144     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/<
20145 _string_0f_82_jump_break:  # (payload array byte)
20146     0x11/imm32/alloc-id:fake:payload
20147     # "0f 82/jump-if-addr< break/disp32"
20148     0x20/imm32/size
20149     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
20150 _string_0f_82_jump_loop:  # (payload array byte)
20151     0x11/imm32/alloc-id:fake:payload
20152     # "0f 82/jump-if-addr< loop/disp32"
20153     0x1f/imm32/size
20154     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
20155 _string_0f_83_jump_label:  # (payload array byte)
20156     0x11/imm32/alloc-id:fake:payload
20157     # "0f 83/jump-if-addr>="
20158     0x14/imm32/size
20159     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/=
20160 _string_0f_83_jump_break:  # (payload array byte)
20161     0x11/imm32/alloc-id:fake:payload
20162     # "0f 83/jump-if-addr>= break/disp32"
20163     0x21/imm32/size
20164     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
20165 _string_0f_83_jump_loop:  # (payload array byte)
20166     0x11/imm32/alloc-id:fake:payload
20167     # "0f 83/jump-if-addr>= loop/disp32"
20168     0x20/imm32/size
20169     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
20170 _string_0f_84_jump_label:  # (payload array byte)
20171     0x11/imm32/alloc-id:fake:payload
20172     # "0f 84/jump-if-="
20173     0xf/imm32/size
20174     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/=
20175 _string_0f_84_jump_break:  # (payload array byte)
20176     0x11/imm32/alloc-id:fake:payload
20177     # "0f 84/jump-if-= break/disp32"
20178     0x1c/imm32/size
20179     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
20180 _string_0f_84_jump_loop:  # (payload array byte)
20181     0x11/imm32/alloc-id:fake:payload
20182     # "0f 84/jump-if-= loop/disp32"
20183     0x1b/imm32/size
20184     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
20185 _string_0f_85_jump_label:  # (payload array byte)
20186     0x11/imm32/alloc-id:fake:payload
20187     # "0f 85/jump-if-!="
20188     0x10/imm32/size
20189     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/=
20190 _string_0f_85_jump_break:  # (payload array byte)
20191     0x11/imm32/alloc-id:fake:payload
20192     # "0f 85/jump-if-!= break/disp32"
20193     0x1d/imm32/size
20194     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
20195 _string_0f_85_jump_loop:  # (payload array byte)
20196     0x11/imm32/alloc-id:fake:payload
20197     # "0f 85/jump-if-!= loop/disp32"
20198     0x1c/imm32/size
20199     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
20200 _string_0f_86_jump_label:  # (payload array byte)
20201     0x11/imm32/alloc-id:fake:payload
20202     # "0f 86/jump-if-addr<="
20203     0x14/imm32/size
20204     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/=
20205 _string_0f_86_jump_break:  # (payload array byte)
20206     0x11/imm32/alloc-id:fake:payload
20207     # "0f 86/jump-if-addr<= break/disp32"
20208     0x21/imm32/size
20209     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
20210 _string_0f_86_jump_loop:  # (payload array byte)
20211     0x11/imm32/alloc-id:fake:payload
20212     # "0f 86/jump-if-addr<= loop/disp32"
20213     0x20/imm32/size
20214     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
20215 _string_0f_87_jump_label:  # (payload array byte)
20216     0x11/imm32/alloc-id:fake:payload
20217     # "0f 87/jump-if-addr>"
20218     0x13/imm32/size
20219     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/>
20220 _string_0f_87_jump_break:  # (payload array byte)
20221     0x11/imm32/alloc-id:fake:payload
20222     # "0f 87/jump-if-addr> break/disp32"
20223     0x20/imm32/size
20224     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
20225 _string_0f_87_jump_loop:  # (payload array byte)
20226     0x11/imm32/alloc-id:fake:payload
20227     # "0f 87/jump-if-addr> loop/disp32"
20228     0x1f/imm32/size
20229     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
20230 _string_0f_8c_jump_label:  # (payload array byte)
20231     0x11/imm32/alloc-id:fake:payload
20232     # "0f 8c/jump-if-<"
20233     0xf/imm32/size
20234     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/<
20235 _string_0f_8c_jump_break:  # (payload array byte)
20236     0x11/imm32/alloc-id:fake:payload
20237     # "0f 8c/jump-if-< break/disp32"
20238     0x1c/imm32/size
20239     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
20240 _string_0f_8c_jump_loop:  # (payload array byte)
20241     0x11/imm32/alloc-id:fake:payload
20242     # "0f 8c/jump-if-< loop/disp32"
20243     0x1b/imm32/size
20244     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
20245 _string_0f_8d_jump_label:  # (payload array byte)
20246     0x11/imm32/alloc-id:fake:payload
20247     # "0f 8d/jump-if->="
20248     0x10/imm32/size
20249     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/=
20250 _string_0f_8d_jump_break:  # (payload array byte)
20251     0x11/imm32/alloc-id:fake:payload
20252     # "0f 8d/jump-if->= break/disp32"
20253     0x1d/imm32/size
20254     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
20255 _string_0f_8d_jump_loop:  # (payload array byte)
20256     0x11/imm32/alloc-id:fake:payload
20257     # "0f 8d/jump-if->= loop/disp32"
20258     0x1c/imm32/size
20259     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
20260 _string_0f_8e_jump_label:  # (payload array byte)
20261     0x11/imm32/alloc-id:fake:payload
20262     # "0f 8e/jump-if-<="
20263     0x10/imm32/size
20264     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/=
20265 _string_0f_8e_jump_break:  # (payload array byte)
20266     0x11/imm32/alloc-id:fake:payload
20267     # "0f 8e/jump-if-<= break/disp32"
20268     0x1d/imm32/size
20269     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
20270 _string_0f_8e_jump_loop:  # (payload array byte)
20271     0x11/imm32/alloc-id:fake:payload
20272     # "0f 8e/jump-if-<= loop/disp32"
20273     0x1c/imm32/size
20274     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
20275 _string_0f_8f_jump_label:  # (payload array byte)
20276     0x11/imm32/alloc-id:fake:payload
20277     # "0f 8f/jump-if->"
20278     0xf/imm32/size
20279     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/>
20280 _string_0f_8f_jump_break:  # (payload array byte)
20281     0x11/imm32/alloc-id:fake:payload
20282     # "0f 8f/jump-if-> break/disp32"
20283     0x1c/imm32/size
20284     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
20285 _string_0f_8f_jump_loop:  # (payload array byte)
20286     0x11/imm32/alloc-id:fake:payload
20287     # "0f 8f/jump-if-> loop/disp32"
20288     0x1b/imm32/size
20289     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
20290 _string_0f_af_multiply:  # (payload array byte)
20291     0x11/imm32/alloc-id:fake:payload
20292     # "0f af/multiply"
20293     0xe/imm32/size
20294     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
20295 _string_21_and_with:  # (payload array byte)
20296     0x11/imm32/alloc-id:fake:payload
20297     # "21/and-with"
20298     0xb/imm32/size
20299     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20300 _string_23_and:  # (payload array byte)
20301     0x11/imm32/alloc-id:fake:payload
20302     # "23/and"
20303     0x6/imm32/size
20304     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
20305 _string_25_and_with_eax:  # (payload array byte)
20306     0x11/imm32/alloc-id:fake:payload
20307     # "25/and-with-eax"
20308     0xf/imm32/size
20309     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
20310 _string_29_subtract_from:  # (payload array byte)
20311     0x11/imm32/alloc-id:fake:payload
20312     # "29/subtract-from"
20313     0x10/imm32/size
20314     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
20315 _string_2b_subtract:  # (payload array byte)
20316     0x11/imm32/alloc-id:fake:payload
20317     # "2b/subtract"
20318     0xb/imm32/size
20319     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
20320 _string_2d_subtract_from_eax:  # (payload array byte)
20321     0x11/imm32/alloc-id:fake:payload
20322     # "2d/subtract-from-eax"
20323     0x14/imm32/size
20324     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
20325 _string_31_xor_with:  # (payload array byte)
20326     0x11/imm32/alloc-id:fake:payload
20327     # "31/xor-with"
20328     0xb/imm32/size
20329     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
20330 _string_33_xor:  # (payload array byte)
20331     0x11/imm32/alloc-id:fake:payload
20332     # "33/xor"
20333     0x6/imm32/size
20334     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
20335 _string_35_xor_with_eax:  # (payload array byte)
20336     0x11/imm32/alloc-id:fake:payload
20337     # "35/xor-with-eax"
20338     0xf/imm32/size
20339     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
20340 _string_39_compare->:  # (payload array byte)
20341     0x11/imm32/alloc-id:fake:payload
20342     # "39/compare->"
20343     0xc/imm32/size
20344     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
20345 _string_3b_compare<-:  # (payload array byte)
20346     0x11/imm32/alloc-id:fake:payload
20347     # "3b/compare<-"
20348     0xc/imm32/size
20349     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
20350 _string_3d_compare_eax_with:  # (payload array byte)
20351     0x11/imm32/alloc-id:fake:payload
20352     # "3d/compare-eax-with"
20353     0x13/imm32/size
20354     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
20355 _string_40_increment_eax:  # (payload array byte)
20356     0x11/imm32/alloc-id:fake:payload
20357     # "40/increment-eax"
20358     0x10/imm32/size
20359     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
20360 _string_41_increment_ecx:  # (payload array byte)
20361     0x11/imm32/alloc-id:fake:payload
20362     # "41/increment-ecx"
20363     0x10/imm32/size
20364     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
20365 _string_42_increment_edx:  # (payload array byte)
20366     0x11/imm32/alloc-id:fake:payload
20367     # "42/increment-edx"
20368     0x10/imm32/size
20369     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
20370 _string_43_increment_ebx:  # (payload array byte)
20371     0x11/imm32/alloc-id:fake:payload
20372     # "43/increment-ebx"
20373     0x10/imm32/size
20374     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
20375 _string_46_increment_esi:  # (payload array byte)
20376     0x11/imm32/alloc-id:fake:payload
20377     # "46/increment-esi"
20378     0x10/imm32/size
20379     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
20380 _string_47_increment_edi:  # (payload array byte)
20381     0x11/imm32/alloc-id:fake:payload
20382     # "47/increment-edi"
20383     0x10/imm32/size
20384     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
20385 _string_48_decrement_eax:  # (payload array byte)
20386     0x11/imm32/alloc-id:fake:payload
20387     # "48/decrement-eax"
20388     0x10/imm32/size
20389     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
20390 _string_49_decrement_ecx:  # (payload array byte)
20391     0x11/imm32/alloc-id:fake:payload
20392     # "49/decrement-ecx"
20393     0x10/imm32/size
20394     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
20395 _string_4a_decrement_edx:  # (payload array byte)
20396     0x11/imm32/alloc-id:fake:payload
20397     # "4a/decrement-edx"
20398     0x10/imm32/size
20399     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
20400 _string_4b_decrement_ebx:  # (payload array byte)
20401     0x11/imm32/alloc-id:fake:payload
20402     # "4b/decrement-ebx"
20403     0x10/imm32/size
20404     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
20405 _string_4e_decrement_esi:  # (payload array byte)
20406     0x11/imm32/alloc-id:fake:payload
20407     # "4e/decrement-esi"
20408     0x10/imm32/size
20409     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
20410 _string_4f_decrement_edi:  # (payload array byte)
20411     0x11/imm32/alloc-id:fake:payload
20412     # "4f/decrement-edi"
20413     0x10/imm32/size
20414     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
20415 _string_81_subop_add:  # (payload array byte)
20416     0x11/imm32/alloc-id:fake:payload
20417     # "81 0/subop/add"
20418     0xe/imm32/size
20419     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
20420 _string_81_subop_or:  # (payload array byte)
20421     0x11/imm32/alloc-id:fake:payload
20422     # "81 1/subop/or"
20423     0xd/imm32/size
20424     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
20425 _string_81_subop_and:  # (payload array byte)
20426     0x11/imm32/alloc-id:fake:payload
20427     # "81 4/subop/and"
20428     0xe/imm32/size
20429     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
20430 _string_81_subop_subtract:  # (payload array byte)
20431     0x11/imm32/alloc-id:fake:payload
20432     # "81 5/subop/subtract"
20433     0x13/imm32/size
20434     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
20435 _string_81_subop_xor:  # (payload array byte)
20436     0x11/imm32/alloc-id:fake:payload
20437     # "81 6/subop/xor"
20438     0xe/imm32/size
20439     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
20440 _string_81_subop_compare:  # (payload array byte)
20441     0x11/imm32/alloc-id:fake:payload
20442     # "81 7/subop/compare"
20443     0x12/imm32/size
20444     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
20445 _string_89_<-:  # (payload array byte)
20446     0x11/imm32/alloc-id:fake:payload
20447     # "89/<-"
20448     0x5/imm32/size
20449     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
20450 _string_8b_->:  # (payload array byte)
20451     0x11/imm32/alloc-id:fake:payload
20452     # "8b/->"
20453     0x5/imm32/size
20454     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
20455 _string_8a_copy_byte:
20456     0x11/imm32/alloc-id:fake:payload
20457     # "8a/byte->"
20458     0x9/imm32/size
20459     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
20460 _string_88_copy_byte:
20461     0x11/imm32/alloc-id:fake:payload
20462     # "88/byte<-"
20463     0x9/imm32/size
20464     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
20465 _string_8d_copy_address:  # (payload array byte)
20466     0x11/imm32/alloc-id:fake:payload
20467     # "8d/copy-address"
20468     0xf/imm32/size
20469     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
20470 _string_b8_copy_to_eax:  # (payload array byte)
20471     0x11/imm32/alloc-id:fake:payload
20472     # "b8/copy-to-eax"
20473     0xe/imm32/size
20474     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
20475 _string_b9_copy_to_ecx:  # (payload array byte)
20476     0x11/imm32/alloc-id:fake:payload
20477     # "b9/copy-to-ecx"
20478     0xe/imm32/size
20479     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
20480 _string_ba_copy_to_edx:  # (payload array byte)
20481     0x11/imm32/alloc-id:fake:payload
20482     # "ba/copy-to-edx"
20483     0xe/imm32/size
20484     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
20485 _string_bb_copy_to_ebx:  # (payload array byte)
20486     0x11/imm32/alloc-id:fake:payload
20487     # "bb/copy-to-ebx"
20488     0xe/imm32/size
20489     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
20490 _string_be_copy_to_esi:  # (payload array byte)
20491     0x11/imm32/alloc-id:fake:payload
20492     # "be/copy-to-esi"
20493     0xe/imm32/size
20494     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
20495 _string_bf_copy_to_edi:  # (payload array byte)
20496     0x11/imm32/alloc-id:fake:payload
20497     # "bf/copy-to-edi"
20498     0xe/imm32/size
20499     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
20500 _string_c7_subop_copy:  # (payload array byte)
20501     0x11/imm32/alloc-id:fake:payload
20502     # "c7 0/subop/copy"
20503     0xf/imm32/size
20504     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
20505 _string_e9_jump_label:  # (payload array byte)
20506     0x11/imm32/alloc-id:fake:payload
20507     # "e9/jump"
20508     0x7/imm32/size
20509     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
20510 _string_e9_jump_break:  # (payload array byte)
20511     0x11/imm32/alloc-id:fake:payload
20512     # "e9/jump break/disp32"
20513     0x14/imm32/size
20514     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
20515 _string_e9_jump_loop:  # (payload array byte)
20516     0x11/imm32/alloc-id:fake:payload
20517     # "e9/jump loop/disp32"
20518     0x13/imm32/size
20519     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
20520 _string_f7_subop_negate:
20521     0x11/imm32/alloc-id:fake:payload
20522     # "f7 3/subop/negate"
20523     0x11/imm32/size
20524     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
20525 _string_ff_subop_increment:  # (payload array byte)
20526     0x11/imm32/alloc-id:fake:payload
20527     # "ff 0/subop/increment"
20528     0x14/imm32/size
20529     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
20530 _string_ff_subop_decrement:  # (payload array byte)
20531     0x11/imm32/alloc-id:fake:payload
20532     # "ff 1/subop/decrement"
20533     0x14/imm32/size
20534     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
20535 _string_c1_subop_shift_left:  # (payload array byte)
20536     0x11/imm32/alloc-id:fake:payload
20537     # "c1/shift 4/subop/left"
20538     0x15/imm32/size
20539     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
20540 _string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
20541     0x11/imm32/alloc-id:fake:payload
20542     # "c1/shift 5/subop/right-padding-zeroes"
20543     0x25/imm32/size
20544     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
20545 _string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
20546     0x11/imm32/alloc-id:fake:payload
20547     # "c1/shift 7/subop/right-preserving-sign"
20548     0x26/imm32/size
20549     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
20550 
20551 Single-int-var-in-mem:  # (payload list var)
20552     0x11/imm32/alloc-id:fake:payload
20553     0x11/imm32/alloc-id:fake
20554     Int-var-in-mem/imm32
20555     0/imm32/next
20556     0/imm32/next
20557 
20558 Int-var-in-mem:  # (payload var)
20559     0x11/imm32/alloc-id:fake:payload
20560     0/imm32/name
20561     0/imm32/name
20562     0x11/imm32/alloc-id:fake
20563     Type-int/imm32
20564     1/imm32/some-block-depth
20565     1/imm32/some-stack-offset
20566     0/imm32/no-register
20567     0/imm32/no-register
20568 
20569 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20570 Single-byte-var-in-mem:  # (payload list var)
20571     0x11/imm32/alloc-id:fake:payload
20572     0x11/imm32/alloc-id:fake
20573     Byte-var-in-mem/imm32
20574     0/imm32/next
20575     0/imm32/next
20576 
20577 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20578 Byte-var-in-mem:  # (payload var)
20579     0x11/imm32/alloc-id:fake:payload
20580     0/imm32/name
20581     0/imm32/name
20582     0x11/imm32/alloc-id:fake
20583     Type-byte/imm32
20584     1/imm32/some-block-depth
20585     1/imm32/some-stack-offset
20586     0/imm32/no-register
20587     0/imm32/no-register
20588 
20589 Two-args-int-stack-int-reg:  # (payload list var)
20590     0x11/imm32/alloc-id:fake:payload
20591     0x11/imm32/alloc-id:fake
20592     Int-var-in-mem/imm32
20593     0x11/imm32/alloc-id:fake
20594     Single-int-var-in-some-register/imm32/next
20595 
20596 Two-int-args-in-regs:  # (payload list var)
20597     0x11/imm32/alloc-id:fake:payload
20598     0x11/imm32/alloc-id:fake
20599     Int-var-in-some-register/imm32
20600     0x11/imm32/alloc-id:fake
20601     Single-int-var-in-some-register/imm32/next
20602 
20603 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
20604 Two-args-byte-stack-byte-reg:  # (payload list var)
20605     0x11/imm32/alloc-id:fake:payload
20606     0x11/imm32/alloc-id:fake
20607     Byte-var-in-mem/imm32
20608     0x11/imm32/alloc-id:fake
20609     Single-byte-var-in-some-register/imm32/next
20610 
20611 Two-args-int-reg-int-stack:  # (payload list var)
20612     0x11/imm32/alloc-id:fake:payload
20613     0x11/imm32/alloc-id:fake
20614     Int-var-in-some-register/imm32
20615     0x11/imm32/alloc-id:fake
20616     Single-int-var-in-mem/imm32/next
20617 
20618 Two-args-int-eax-int-literal:  # (payload list var)
20619     0x11/imm32/alloc-id:fake:payload
20620     0x11/imm32/alloc-id:fake
20621     Int-var-in-eax/imm32
20622     0x11/imm32/alloc-id:fake
20623     Single-lit-var/imm32/next
20624 
20625 Int-var-and-literal:  # (payload list var)
20626     0x11/imm32/alloc-id:fake:payload
20627     0x11/imm32/alloc-id:fake
20628     Int-var-in-mem/imm32
20629     0x11/imm32/alloc-id:fake
20630     Single-lit-var/imm32/next
20631 
20632 Int-var-in-register-and-literal:  # (payload list var)
20633     0x11/imm32/alloc-id:fake:payload
20634     0x11/imm32/alloc-id:fake
20635     Int-var-in-some-register/imm32
20636     0x11/imm32/alloc-id:fake
20637     Single-lit-var/imm32/next
20638 
20639 Single-int-var-in-some-register:  # (payload list var)
20640     0x11/imm32/alloc-id:fake:payload
20641     0x11/imm32/alloc-id:fake
20642     Int-var-in-some-register/imm32
20643     0/imm32/next
20644     0/imm32/next
20645 
20646 Single-addr-var-in-some-register:  # (payload list var)
20647     0x11/imm32/alloc-id:fake:payload
20648     0x11/imm32/alloc-id:fake
20649     Addr-var-in-some-register/imm32
20650     0/imm32/next
20651     0/imm32/next
20652 
20653 Single-byte-var-in-some-register:  # (payload list var)
20654     0x11/imm32/alloc-id:fake:payload
20655     0x11/imm32/alloc-id:fake
20656     Byte-var-in-some-register/imm32
20657     0/imm32/next
20658     0/imm32/next
20659 
20660 Int-var-in-some-register:  # (payload var)
20661     0x11/imm32/alloc-id:fake:payload
20662     0/imm32/name
20663     0/imm32/name
20664     0x11/imm32/alloc-id:fake
20665     Type-int/imm32
20666     1/imm32/some-block-depth
20667     0/imm32/no-stack-offset
20668     0x11/imm32/alloc-id:fake
20669     Any-register/imm32
20670 
20671 Any-register:  # (payload array byte)
20672     0x11/imm32/alloc-id:fake:payload
20673     1/imm32/size
20674     # data
20675     2a/asterisk
20676 
20677 Addr-var-in-some-register:  # (payload var)
20678     0x11/imm32/alloc-id:fake:payload
20679     0/imm32/name
20680     0/imm32/name
20681     0x11/imm32/alloc-id:fake
20682     Type-addr/imm32
20683     1/imm32/some-block-depth
20684     0/imm32/no-stack-offset
20685     0x11/imm32/alloc-id:fake
20686     Any-register/imm32
20687 
20688 Byte-var-in-some-register:  # (payload var)
20689     0x11/imm32/alloc-id:fake:payload
20690     0/imm32/name
20691     0/imm32/name
20692     0x11/imm32/alloc-id:fake
20693     Type-byte/imm32
20694     1/imm32/some-block-depth
20695     0/imm32/no-stack-offset
20696     0x11/imm32/alloc-id:fake
20697     Any-register/imm32
20698 
20699 Single-int-var-in-eax:  # (payload list var)
20700     0x11/imm32/alloc-id:fake:payload
20701     0x11/imm32/alloc-id:fake
20702     Int-var-in-eax/imm32
20703     0/imm32/next
20704     0/imm32/next
20705 
20706 Int-var-in-eax:
20707     0x11/imm32/alloc-id:fake:payload
20708     0/imm32/name
20709     0/imm32/name
20710     0x11/imm32/alloc-id:fake
20711     Type-int/imm32
20712     1/imm32/some-block-depth
20713     0/imm32/no-stack-offset
20714     0x11/imm32/alloc-id:fake
20715     $Register-eax/imm32
20716 
20717 Single-int-var-in-ecx:  # (payload list var)
20718     0x11/imm32/alloc-id:fake:payload
20719     0x11/imm32/alloc-id:fake
20720     Int-var-in-ecx/imm32
20721     0/imm32/next
20722     0/imm32/next
20723 
20724 Int-var-in-ecx:
20725     0x11/imm32/alloc-id:fake:payload
20726     0/imm32/name
20727     0/imm32/name
20728     0x11/imm32/alloc-id:fake
20729     Type-int/imm32
20730     1/imm32/some-block-depth
20731     0/imm32/no-stack-offset
20732     0x11/imm32/alloc-id:fake
20733     $Register-ecx/imm32/register
20734 
20735 Single-int-var-in-edx:  # (payload list var)
20736     0x11/imm32/alloc-id:fake:payload
20737     0x11/imm32/alloc-id:fake
20738     Int-var-in-edx/imm32
20739     0/imm32/next
20740     0/imm32/next
20741 
20742 Int-var-in-edx:  # (payload list var)
20743     0x11/imm32/alloc-id:fake:payload
20744     0/imm32/name
20745     0/imm32/name
20746     0x11/imm32/alloc-id:fake
20747     Type-int/imm32
20748     1/imm32/some-block-depth
20749     0/imm32/no-stack-offset
20750     0x11/imm32/alloc-id:fake
20751     $Register-edx/imm32/register
20752 
20753 Single-int-var-in-ebx:  # (payload list var)
20754     0x11/imm32/alloc-id:fake:payload
20755     0x11/imm32/alloc-id:fake
20756     Int-var-in-ebx/imm32
20757     0/imm32/next
20758     0/imm32/next
20759 
20760 Int-var-in-ebx:  # (payload list var)
20761     0x11/imm32/alloc-id:fake:payload
20762     0/imm32/name
20763     0/imm32/name
20764     0x11/imm32/alloc-id:fake
20765     Type-int/imm32
20766     1/imm32/some-block-depth
20767     0/imm32/no-stack-offset
20768     0x11/imm32/alloc-id:fake
20769     $Register-ebx/imm32/register
20770 
20771 Single-int-var-in-esi:  # (payload list var)
20772     0x11/imm32/alloc-id:fake:payload
20773     0x11/imm32/alloc-id:fake
20774     Int-var-in-esi/imm32
20775     0/imm32/next
20776     0/imm32/next
20777 
20778 Int-var-in-esi:  # (payload list var)
20779     0x11/imm32/alloc-id:fake:payload
20780     0/imm32/name
20781     0/imm32/name
20782     0x11/imm32/alloc-id:fake
20783     Type-int/imm32
20784     1/imm32/some-block-depth
20785     0/imm32/no-stack-offset
20786     0x11/imm32/alloc-id:fake
20787     $Register-esi/imm32/register
20788 
20789 Single-int-var-in-edi:  # (payload list var)
20790     0x11/imm32/alloc-id:fake:payload
20791     0x11/imm32/alloc-id:fake
20792     Int-var-in-edi/imm32
20793     0/imm32/next
20794     0/imm32/next
20795 
20796 Int-var-in-edi:  # (payload list var)
20797     0x11/imm32/alloc-id:fake:payload
20798     0/imm32/name
20799     0/imm32/name
20800     0x11/imm32/alloc-id:fake
20801     Type-int/imm32
20802     1/imm32/some-block-depth
20803     0/imm32/no-stack-offset
20804     0x11/imm32/alloc-id:fake
20805     $Register-edi/imm32/register
20806 
20807 Single-lit-var:  # (payload list var)
20808     0x11/imm32/alloc-id:fake:payload
20809     0x11/imm32/alloc-id:fake
20810     Lit-var/imm32
20811     0/imm32/next
20812     0/imm32/next
20813 
20814 Lit-var:  # (payload var)
20815     0x11/imm32/alloc-id:fake:payload
20816     0/imm32/name
20817     0/imm32/name
20818     0x11/imm32/alloc-id:fake
20819     Type-literal/imm32
20820     1/imm32/some-block-depth
20821     0/imm32/no-stack-offset
20822     0/imm32/no-register
20823     0/imm32/no-register
20824 
20825 Type-int:  # (payload type-tree)
20826     0x11/imm32/alloc-id:fake:payload
20827     1/imm32/is-atom
20828     1/imm32/value:int
20829     0/imm32/left:unused
20830     0/imm32/right:null
20831     0/imm32/right:null
20832 
20833 Type-literal:  # (payload type-tree)
20834     0x11/imm32/alloc-id:fake:payload
20835     1/imm32/is-atom
20836     0/imm32/value:literal
20837     0/imm32/left:unused
20838     0/imm32/right:null
20839     0/imm32/right:null
20840 
20841 Type-addr:  # (payload type-tree)
20842     0x11/imm32/alloc-id:fake:payload
20843     1/imm32/is-atom
20844     2/imm32/value:addr
20845     0/imm32/left:unused
20846     0/imm32/right:null
20847     0/imm32/right:null
20848 
20849 Type-byte:  # (payload type-tree)
20850     0x11/imm32/alloc-id:fake:payload
20851     1/imm32/is-atom
20852     8/imm32/value:byte
20853     0/imm32/left:unused
20854     0/imm32/right:null
20855     0/imm32/right:null
20856 
20857 == code
20858 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
20859     # . prologue
20860     55/push-ebp
20861     89/<- %ebp 4/r32/esp
20862     # . save registers
20863     50/push-eax
20864     51/push-ecx
20865     # ecx = primitive
20866     8b/-> *(ebp+0x10) 1/r32/ecx
20867     # emit primitive name
20868     (emit-indent *(ebp+8) *Curr-block-depth)
20869     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
20870     (write-buffered *(ebp+8) %eax)
20871     # emit rm32 if necessary
20872     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
20873     # emit r32 if necessary
20874     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
20875     # emit imm32 if necessary
20876     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
20877     # emit imm8 if necessary
20878     (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
20879     # emit disp32 if necessary
20880     (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
20881     (write-buffered *(ebp+8) Newline)
20882 $emit-subx-primitive:end:
20883     # . restore registers
20884     59/pop-to-ecx
20885     58/pop-to-eax
20886     # . epilogue
20887     89/<- %esp 5/r32/ebp
20888     5d/pop-to-ebp
20889     c3/return
20890 
20891 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
20892     # . prologue
20893     55/push-ebp
20894     89/<- %ebp 4/r32/esp
20895     # . save registers
20896     50/push-eax
20897     # if (l == 0) return
20898     81 7/subop/compare *(ebp+0xc) 0/imm32
20899     74/jump-if-= $emit-subx-rm32:end/disp8
20900     # var v/eax: (addr stmt-var)
20901     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
20902     (emit-subx-var-as-rm32 *(ebp+8) %eax)
20903 $emit-subx-rm32:end:
20904     # . restore registers
20905     58/pop-to-eax
20906     # . epilogue
20907     89/<- %esp 5/r32/ebp
20908     5d/pop-to-ebp
20909     c3/return
20910 
20911 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)
20912     # . prologue
20913     55/push-ebp
20914     89/<- %ebp 4/r32/esp
20915     # . save registers
20916     51/push-ecx
20917     # eax = l
20918     8b/-> *(ebp+0xc) 0/r32/eax
20919     # ecx = stmt
20920     8b/-> *(ebp+8) 1/r32/ecx
20921     # if (l == 1) return stmt->inouts
20922     {
20923       3d/compare-eax-and 1/imm32
20924       75/jump-if-!= break/disp8
20925 $get-stmt-operand-from-arg-location:1:
20926       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20927       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20928     }
20929     # if (l == 2) return stmt->inouts->next
20930     {
20931       3d/compare-eax-and 2/imm32
20932       75/jump-if-!= break/disp8
20933 $get-stmt-operand-from-arg-location:2:
20934       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
20935       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
20936       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20937     }
20938     # if (l == 3) return stmt->outputs
20939     {
20940       3d/compare-eax-and 3/imm32
20941       75/jump-if-!= break/disp8
20942 $get-stmt-operand-from-arg-location:3:
20943       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
20944       eb/jump $get-stmt-operand-from-arg-location:end/disp8
20945     }
20946     # abort
20947     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
20948 $get-stmt-operand-from-arg-location:end:
20949     # . restore registers
20950     59/pop-to-ecx
20951     # . epilogue
20952     89/<- %esp 5/r32/ebp
20953     5d/pop-to-ebp
20954     c3/return
20955 
20956 $get-stmt-operand-from-arg-location:abort:
20957     # error("invalid arg-location " eax)
20958     (write-buffered *(ebp+0x10) "invalid arg-location ")
20959     (write-int32-hex-buffered *(ebp+0x10) %eax)
20960     (write-buffered *(ebp+0x10) Newline)
20961     (flush *(ebp+0x10))
20962     (stop *(ebp+0x14) 1)
20963     # never gets here
20964 
20965 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20966     # . prologue
20967     55/push-ebp
20968     89/<- %ebp 4/r32/esp
20969     # . save registers
20970     50/push-eax
20971     51/push-ecx
20972     # if (l == 0) return
20973     81 7/subop/compare *(ebp+0xc) 0/imm32
20974     0f 84/jump-if-= $emit-subx-r32:end/disp32
20975     # var v/eax: (addr stmt-var)
20976     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
20977     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
20978     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
20979     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
20980     (write-buffered *(ebp+8) Space)
20981     (write-int32-hex-buffered *(ebp+8) *eax)
20982     (write-buffered *(ebp+8) "/r32")
20983 $emit-subx-r32:end:
20984     # . restore registers
20985     59/pop-to-ecx
20986     58/pop-to-eax
20987     # . epilogue
20988     89/<- %esp 5/r32/ebp
20989     5d/pop-to-ebp
20990     c3/return
20991 
20992 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
20993     # . prologue
20994     55/push-ebp
20995     89/<- %ebp 4/r32/esp
20996     # . save registers
20997     50/push-eax
20998     51/push-ecx
20999     # if (l == 0) return
21000     81 7/subop/compare *(ebp+0xc) 0/imm32
21001     0f 84/jump-if-= $emit-subx-imm32:end/disp32
21002     # var v/eax: (handle var)
21003     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
21004     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
21005     (lookup *eax *(eax+4))  # Var-name Var-name => eax
21006     (write-buffered *(ebp+8) Space)
21007     (write-buffered *(ebp+8) %eax)
21008     (write-buffered *(ebp+8) "/imm32")
21009 $emit-subx-imm32:end:
21010     # . restore registers
21011     59/pop-to-ecx
21012     58/pop-to-eax
21013     # . epilogue
21014     89/<- %esp 5/r32/ebp
21015     5d/pop-to-ebp
21016     c3/return
21017 
21018 emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
21019     # . prologue
21020     55/push-ebp
21021     89/<- %ebp 4/r32/esp
21022     # . save registers
21023     50/push-eax
21024     51/push-ecx
21025     # if (l == 0) return
21026     81 7/subop/compare *(ebp+0xc) 0/imm32
21027     0f 84/jump-if-= $emit-subx-imm32:end/disp32
21028     # var v/eax: (handle var)
21029     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
21030     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
21031     (lookup *eax *(eax+4))  # Var-name Var-name => eax
21032     (write-buffered *(ebp+8) Space)
21033     (write-buffered *(ebp+8) %eax)
21034     (write-buffered *(ebp+8) "/imm8")
21035 $emit-subx-imm8:end:
21036     # . restore registers
21037     59/pop-to-ecx
21038     58/pop-to-eax
21039     # . epilogue
21040     89/<- %esp 5/r32/ebp
21041     5d/pop-to-ebp
21042     c3/return
21043 
21044 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
21045     # . prologue
21046     55/push-ebp
21047     89/<- %ebp 4/r32/esp
21048     # . save registers
21049     50/push-eax
21050     51/push-ecx
21051     # if (location == 0) return
21052     81 7/subop/compare *(ebp+0xc) 0/imm32
21053     0f 84/jump-if-= $emit-subx-disp32:end/disp32
21054     # var v/eax: (addr stmt-var)
21055     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
21056     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
21057     (lookup *eax *(eax+4))  # Var-name Var-name => eax
21058     (write-buffered *(ebp+8) Space)
21059     (write-buffered *(ebp+8) %eax)
21060     # hack: if instruction operation starts with "break", emit ":break"
21061     # var name/ecx: (addr array byte) = lookup(stmt->operation)
21062     8b/-> *(ebp+0x10) 0/r32/eax
21063     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21064     89/<- %ecx 0/r32/eax
21065     {
21066       (string-starts-with? %ecx "break")  # => eax
21067       3d/compare-eax-and 0/imm32/false
21068       74/jump-if-= break/disp8
21069       (write-buffered *(ebp+8) ":break")
21070     }
21071     # hack: if instruction operation starts with "loop", emit ":loop"
21072     {
21073       (string-starts-with? %ecx "loop")  # => eax
21074       3d/compare-eax-and 0/imm32/false
21075       74/jump-if-= break/disp8
21076       (write-buffered *(ebp+8) ":loop")
21077     }
21078     (write-buffered *(ebp+8) "/disp32")
21079 $emit-subx-disp32:end:
21080     # . restore registers
21081     59/pop-to-ecx
21082     58/pop-to-eax
21083     # . epilogue
21084     89/<- %esp 5/r32/ebp
21085     5d/pop-to-ebp
21086     c3/return
21087 
21088 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
21089     # . prologue
21090     55/push-ebp
21091     89/<- %ebp 4/r32/esp
21092     # . save registers
21093     50/push-eax
21094     51/push-ecx
21095     #
21096     (emit-indent *(ebp+8) *Curr-block-depth)
21097     (write-buffered *(ebp+8) "(")
21098     # ecx = stmt
21099     8b/-> *(ebp+0xc) 1/r32/ecx
21100     # - emit function name
21101     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
21102     (write-buffered *(ebp+8) %eax)
21103     # - emit arguments
21104     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
21105     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
21106     {
21107       # if (curr == null) break
21108       3d/compare-eax-and 0/imm32
21109       74/jump-if-= break/disp8
21110       #
21111       (emit-subx-call-operand *(ebp+8) %eax)
21112       # curr = lookup(curr->next)
21113       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
21114       eb/jump loop/disp8
21115     }
21116     #
21117     (write-buffered *(ebp+8) ")\n")
21118 $emit-call:end:
21119     # . restore registers
21120     59/pop-to-ecx
21121     58/pop-to-eax
21122     # . epilogue
21123     89/<- %esp 5/r32/ebp
21124     5d/pop-to-ebp
21125     c3/return
21126 
21127 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
21128     # shares code with emit-subx-var-as-rm32
21129     # . prologue
21130     55/push-ebp
21131     89/<- %ebp 4/r32/esp
21132     # . save registers
21133     50/push-eax
21134     51/push-ecx
21135     56/push-esi
21136     # ecx = s
21137     8b/-> *(ebp+0xc) 1/r32/ecx
21138     # var operand/esi: (addr var) = lookup(s->value)
21139     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21140     89/<- %esi 0/r32/eax
21141     # if (operand->register && !s->is-deref?) emit "%__"
21142     {
21143 $emit-subx-call-operand:check-for-register-direct:
21144       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21145       74/jump-if-= break/disp8
21146       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21147       75/jump-if-!= break/disp8
21148 $emit-subx-call-operand:register-direct:
21149       (write-buffered *(ebp+8) " %")
21150       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21151       (write-buffered *(ebp+8) %eax)
21152       e9/jump $emit-subx-call-operand:end/disp32
21153     }
21154     # else if (operand->register && s->is-deref?) emit "*__"
21155     {
21156 $emit-subx-call-operand:check-for-register-indirect:
21157       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21158       74/jump-if-= break/disp8
21159       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21160       74/jump-if-= break/disp8
21161 $emit-subx-call-operand:register-indirect:
21162       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
21163       e9/jump $emit-subx-call-operand:end/disp32
21164     }
21165     # else if (operand->stack-offset) emit "*(ebp+__)"
21166     {
21167       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
21168       74/jump-if-= break/disp8
21169 $emit-subx-call-operand:stack:
21170       (emit-subx-call-operand-stack *(ebp+8) %esi)
21171       e9/jump $emit-subx-call-operand:end/disp32
21172     }
21173     # else if (operand->type == literal) emit "__"
21174     {
21175       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
21176       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
21177       75/jump-if-!= break/disp8
21178 $emit-subx-call-operand:literal:
21179       (write-buffered *(ebp+8) Space)
21180       (lookup *esi *(esi+4))  # Var-name Var-name => eax
21181       (write-buffered *(ebp+8) %eax)
21182     }
21183 $emit-subx-call-operand:end:
21184     # . restore registers
21185     5e/pop-to-esi
21186     59/pop-to-ecx
21187     58/pop-to-eax
21188     # . epilogue
21189     89/<- %esp 5/r32/ebp
21190     5d/pop-to-ebp
21191     c3/return
21192 
21193 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
21194     # . prologue
21195     55/push-ebp
21196     89/<- %ebp 4/r32/esp
21197     # . save registers
21198     50/push-eax
21199     51/push-ecx
21200     56/push-esi
21201     # esi = v
21202     8b/-> *(ebp+0xc) 6/r32/esi
21203     # var size/ecx: int = size-of-deref(v)
21204     (size-of-deref %esi)  # => eax
21205     89/<- %ecx 0/r32/eax
21206     # var reg-name/esi: (addr array byte) = lookup(v->register)
21207     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21208     89/<- %esi 0/r32/eax
21209     # TODO: assert size is a multiple of 4
21210     # var i/eax: int = 0
21211     b8/copy-to-eax 0/imm32
21212     {
21213 $emit-subx-call-operand-register-indirect:loop:
21214       # if (i >= size) break
21215       39/compare %eax 1/r32/ecx
21216       7d/jump-if->= break/disp8
21217       # emit " *(" v->register "+" i ")"
21218       (write-buffered *(ebp+8) " *(")
21219       (write-buffered *(ebp+8) %esi)
21220       (write-buffered *(ebp+8) "+")
21221       (write-int32-hex-buffered *(ebp+8) %eax)
21222       (write-buffered *(ebp+8) ")")
21223       # i += 4
21224       05/add-to-eax 4/imm32
21225       #
21226       eb/jump loop/disp8
21227     }
21228 $emit-subx-call-operand-register-indirect:end:
21229     # . restore registers
21230     5e/pop-to-esi
21231     59/pop-to-ecx
21232     58/pop-to-eax
21233     # . epilogue
21234     89/<- %esp 5/r32/ebp
21235     5d/pop-to-ebp
21236     c3/return
21237 
21238 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
21239     # . prologue
21240     55/push-ebp
21241     89/<- %ebp 4/r32/esp
21242     # . save registers
21243     50/push-eax
21244     51/push-ecx
21245     56/push-esi
21246     # esi = v
21247     8b/-> *(ebp+0xc) 6/r32/esi
21248     # var curr/ecx: int = v->offset
21249     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
21250     # var max/eax: int = v->offset + size-of(v)
21251     (size-of %esi)  # => eax
21252     # TODO: assert size is a multiple of 4
21253     01/add-to %eax 1/r32/ecx
21254     {
21255 $emit-subx-call-operand-stack:loop:
21256       # if (curr >= max) break
21257       39/compare %ecx 0/r32/eax
21258       7d/jump-if->= break/disp8
21259       # emit " *(ebp+" curr ")"
21260       (write-buffered *(ebp+8) " *(ebp+")
21261       (write-int32-hex-buffered *(ebp+8) %ecx)
21262       (write-buffered *(ebp+8) ")")
21263       # i += 4
21264       81 0/subop/add %ecx 4/imm32
21265       #
21266       eb/jump loop/disp8
21267     }
21268 $emit-subx-call-operand-stack:end:
21269     # . restore registers
21270     5e/pop-to-esi
21271     59/pop-to-ecx
21272     58/pop-to-eax
21273     # . epilogue
21274     89/<- %esp 5/r32/ebp
21275     5d/pop-to-ebp
21276     c3/return
21277 
21278 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
21279     # . prologue
21280     55/push-ebp
21281     89/<- %ebp 4/r32/esp
21282     # . save registers
21283     50/push-eax
21284     51/push-ecx
21285     56/push-esi
21286     # ecx = s
21287     8b/-> *(ebp+0xc) 1/r32/ecx
21288     # var operand/esi: (addr var) = lookup(s->value)
21289     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21290     89/<- %esi 0/r32/eax
21291     # if (operand->register && s->is-deref?) emit "*__"
21292     {
21293 $emit-subx-var-as-rm32:check-for-register-indirect:
21294       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21295       74/jump-if-= break/disp8
21296       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21297       74/jump-if-= break/disp8
21298 $emit-subx-var-as-rm32:register-indirect:
21299       (write-buffered *(ebp+8) " *")
21300       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21301       (write-buffered *(ebp+8) %eax)
21302       e9/jump $emit-subx-var-as-rm32:end/disp32
21303     }
21304     # if (operand->register && !s->is-deref?) emit "%__"
21305     {
21306 $emit-subx-var-as-rm32:check-for-register-direct:
21307       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21308       74/jump-if-= break/disp8
21309       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21310       75/jump-if-!= break/disp8
21311 $emit-subx-var-as-rm32:register-direct:
21312       (write-buffered *(ebp+8) " %")
21313       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21314       (write-buffered *(ebp+8) %eax)
21315       e9/jump $emit-subx-var-as-rm32:end/disp32
21316     }
21317     # else if (operand->stack-offset) emit "*(ebp+__)"
21318     {
21319       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
21320       74/jump-if-= break/disp8
21321 $emit-subx-var-as-rm32:stack:
21322       (write-buffered *(ebp+8) Space)
21323       (write-buffered *(ebp+8) "*(ebp+")
21324       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
21325       (write-buffered *(ebp+8) ")")
21326     }
21327 $emit-subx-var-as-rm32:end:
21328     # . restore registers
21329     5e/pop-to-esi
21330     59/pop-to-ecx
21331     58/pop-to-eax
21332     # . epilogue
21333     89/<- %esp 5/r32/ebp
21334     5d/pop-to-ebp
21335     c3/return
21336 
21337 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
21338     # . prologue
21339     55/push-ebp
21340     89/<- %ebp 4/r32/esp
21341     # . save registers
21342     51/push-ecx
21343     # var curr/ecx: (addr primitive) = primitives
21344     8b/-> *(ebp+8) 1/r32/ecx
21345     {
21346 $find-matching-primitive:loop:
21347       # if (curr == null) break
21348       81 7/subop/compare %ecx 0/imm32
21349       74/jump-if-= break/disp8
21350       # if match(curr, stmt) return curr
21351       {
21352         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
21353         3d/compare-eax-and 0/imm32/false
21354         74/jump-if-= break/disp8
21355         89/<- %eax 1/r32/ecx
21356         eb/jump $find-matching-primitive:end/disp8
21357       }
21358 $find-matching-primitive:next-primitive:
21359       # curr = curr->next
21360       (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
21361       89/<- %ecx 0/r32/eax
21362       #
21363       e9/jump loop/disp32
21364     }
21365     # return null
21366     b8/copy-to-eax 0/imm32
21367 $find-matching-primitive:end:
21368     # . restore registers
21369     59/pop-to-ecx
21370     # . epilogue
21371     89/<- %esp 5/r32/ebp
21372     5d/pop-to-ebp
21373     c3/return
21374 
21375 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
21376     # A mu stmt matches a primitive if the name matches, all the inout vars
21377     # match, and all the output vars match.
21378     # Vars match if types match and registers match.
21379     # In addition, a stmt output matches a primitive's output if types match
21380     # and the primitive has a wildcard register.
21381     # . prologue
21382     55/push-ebp
21383     89/<- %ebp 4/r32/esp
21384     # . save registers
21385     51/push-ecx
21386     52/push-edx
21387     53/push-ebx
21388     56/push-esi
21389     57/push-edi
21390     # ecx = stmt
21391     8b/-> *(ebp+8) 1/r32/ecx
21392     # edx = primitive
21393     8b/-> *(ebp+0xc) 2/r32/edx
21394     {
21395 $mu-stmt-matches-primitive?:check-name:
21396       # if (primitive->name != stmt->operation) return false
21397       # . var esi: (addr array byte) = lookup(stmt->operation)
21398       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
21399       89/<- %esi 0/r32/eax
21400       # . var edi: (addr array byte) = lookup(primitive->name)
21401       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
21402       89/<- %edi 0/r32/eax
21403       (string-equal? %esi %edi)  # => eax
21404       3d/compare-eax-and 0/imm32/false
21405       75/jump-if-!= break/disp8
21406       b8/copy-to-eax 0/imm32
21407       e9/jump $mu-stmt-matches-primitive?:end/disp32
21408     }
21409     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
21410     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
21411     89/<- %esi 0/r32/eax
21412     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
21413     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
21414     89/<- %edi 0/r32/eax
21415     {
21416 $mu-stmt-matches-primitive?:inouts-loop:
21417       # if (curr == 0 && curr2 == 0) move on to check outputs
21418       {
21419 $mu-stmt-matches-primitive?:check-both-inouts-null:
21420         81 7/subop/compare %esi 0/imm32
21421         75/jump-if-!= break/disp8
21422 $mu-stmt-matches-primitive?:stmt-inout-null:
21423         81 7/subop/compare %edi 0/imm32
21424         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
21425 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
21426         # return false
21427         b8/copy-to-eax 0/imm32/false
21428         e9/jump $mu-stmt-matches-primitive?:end/disp32
21429       }
21430       # if (curr2 == 0) return false
21431       {
21432 $mu-stmt-matches-primitive?:check-prim-inout-null:
21433         81 7/subop/compare %edi 0/imm32
21434         75/jump-if-!= break/disp8
21435 $mu-stmt-matches-primitive?:prim-inout-null:
21436         b8/copy-to-eax 0/imm32/false
21437         e9/jump $mu-stmt-matches-primitive?:end/disp32
21438       }
21439       # if (curr != curr2) return false
21440       {
21441 $mu-stmt-matches-primitive?:check-inouts-match:
21442         (lookup *edi *(edi+4))  # List-value List-value => eax
21443         (operand-matches-primitive? %esi %eax)  # => eax
21444         3d/compare-eax-and 0/imm32/false
21445         75/jump-if-!= break/disp8
21446 $mu-stmt-matches-primitive?:inouts-match:
21447         b8/copy-to-eax 0/imm32/false
21448         e9/jump $mu-stmt-matches-primitive?:end/disp32
21449       }
21450 $mu-stmt-matches-primitive?:next-inout:
21451       # curr = lookup(curr->next)
21452       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21453       89/<- %esi 0/r32/eax
21454       # curr2 = lookup(curr2->next)
21455       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21456       89/<- %edi 0/r32/eax
21457       #
21458       e9/jump loop/disp32
21459     }
21460 $mu-stmt-matches-primitive?:check-outputs:
21461     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
21462     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
21463     89/<- %esi 0/r32/eax
21464     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
21465     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
21466     89/<- %edi 0/r32/eax
21467     {
21468 $mu-stmt-matches-primitive?:outputs-loop:
21469       # if (curr == 0) return (curr2 == 0)
21470       {
21471 $mu-stmt-matches-primitive?:check-both-outputs-null:
21472         81 7/subop/compare %esi 0/imm32
21473         75/jump-if-!= break/disp8
21474         {
21475 $mu-stmt-matches-primitive?:stmt-output-null:
21476           81 7/subop/compare %edi 0/imm32
21477           75/jump-if-!= break/disp8
21478 $mu-stmt-matches-primitive?:both-outputs-null:
21479           # return true
21480           b8/copy-to-eax 1/imm32
21481           e9/jump $mu-stmt-matches-primitive?:end/disp32
21482         }
21483 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
21484         # return false
21485         b8/copy-to-eax 0/imm32
21486         e9/jump $mu-stmt-matches-primitive?:end/disp32
21487       }
21488       # if (curr2 == 0) return false
21489       {
21490 $mu-stmt-matches-primitive?:check-prim-output-null:
21491         81 7/subop/compare %edi 0/imm32
21492         75/jump-if-!= break/disp8
21493 $mu-stmt-matches-primitive?:prim-output-is-null:
21494         b8/copy-to-eax 0/imm32
21495         e9/jump $mu-stmt-matches-primitive?:end/disp32
21496       }
21497       # if (curr != curr2) return false
21498       {
21499 $mu-stmt-matches-primitive?:check-outputs-match:
21500         (lookup *edi *(edi+4))  # List-value List-value => eax
21501         (operand-matches-primitive? %esi %eax)  # => eax
21502         3d/compare-eax-and 0/imm32/false
21503         75/jump-if-!= break/disp8
21504 $mu-stmt-matches-primitive?:outputs-match:
21505         b8/copy-to-eax 0/imm32
21506         e9/jump $mu-stmt-matches-primitive?:end/disp32
21507       }
21508 $mu-stmt-matches-primitive?:next-output:
21509       # curr = lookup(curr->next)
21510       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
21511       89/<- %esi 0/r32/eax
21512       # curr2 = lookup(curr2->next)
21513       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
21514       89/<- %edi 0/r32/eax
21515       #
21516       e9/jump loop/disp32
21517     }
21518 $mu-stmt-matches-primitive?:return-true:
21519     b8/copy-to-eax 1/imm32
21520 $mu-stmt-matches-primitive?:end:
21521     # . restore registers
21522     5f/pop-to-edi
21523     5e/pop-to-esi
21524     5b/pop-to-ebx
21525     5a/pop-to-edx
21526     59/pop-to-ecx
21527     # . epilogue
21528     89/<- %esp 5/r32/ebp
21529     5d/pop-to-ebp
21530     c3/return
21531 
21532 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
21533     # . prologue
21534     55/push-ebp
21535     89/<- %ebp 4/r32/esp
21536     # . save registers
21537     51/push-ecx
21538     52/push-edx
21539     53/push-ebx
21540     56/push-esi
21541     57/push-edi
21542     # ecx = s
21543     8b/-> *(ebp+8) 1/r32/ecx
21544     # var var/esi: (addr var) = lookup(s->value)
21545     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
21546     89/<- %esi 0/r32/eax
21547     # edi = prim-var
21548     8b/-> *(ebp+0xc) 7/r32/edi
21549 $operand-matches-primitive?:check-type:
21550     # if !category-match?(var->type, prim-var->type) return false
21551     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
21552     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
21553     89/<- %ebx 0/r32/eax
21554     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
21555     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
21556     (subx-type-category-match? %ebx %eax)  # => eax
21557     3d/compare-eax-and 0/imm32/false
21558     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
21559     {
21560 $operand-matches-primitive?:check-register:
21561       # if prim-var is in memory and var is in register but dereference, match
21562       {
21563         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21564         0f 85/jump-if-!= break/disp32
21565         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21566         74/jump-if-= break/disp8
21567         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21568         74/jump-if-= break/disp8
21569 $operand-matches-primitive?:var-deref-match:
21570         e9/jump $operand-matches-primitive?:return-true/disp32
21571       }
21572       # if prim-var is in register and var is in register but dereference, no match
21573       {
21574         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
21575         0f 84/jump-if-= break/disp32
21576         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
21577         0f 84/jump-if-= break/disp32
21578         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
21579         74/jump-if-= break/disp8
21580 $operand-matches-primitive?:var-deref-no-match:
21581         e9/jump $operand-matches-primitive?:return-false/disp32
21582       }
21583       # return false if var->register doesn't match prim-var->register
21584       {
21585         # if register addresses are equal, it's a match
21586         # var vreg/ebx: (addr array byte) = lookup(var->register)
21587         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
21588         89/<- %ebx 0/r32/eax
21589         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
21590         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
21591         89/<- %ecx 0/r32/eax
21592         # if (vreg == preg) break
21593         39/compare %ecx 3/r32/ebx
21594         74/jump-if-= break/disp8
21595 $operand-matches-primitive?:var-register-no-match:
21596         # if either address is 0, return false
21597         81 7/subop/compare %ebx 0/imm32
21598         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21599         81 7/subop/compare %ecx 0/imm32
21600         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
21601         # if prim-var->register is wildcard, it's a match
21602         (string-equal? %ecx "*")  # Any-register => eax
21603         3d/compare-eax-and 0/imm32/false
21604         75/jump-if-!= break/disp8
21605 $operand-matches-primitive?:wildcard-no-match:
21606         # if string contents aren't equal, return false
21607         (string-equal? %ecx %ebx)  # => eax
21608         3d/compare-eax-and 0/imm32/false
21609         74/jump-if-= $operand-matches-primitive?:return-false/disp8
21610       }
21611     }
21612 $operand-matches-primitive?:return-true:
21613     b8/copy-to-eax 1/imm32/true
21614     eb/jump $operand-matches-primitive?:end/disp8
21615 $operand-matches-primitive?:return-false:
21616     b8/copy-to-eax 0/imm32/false
21617 $operand-matches-primitive?:end:
21618     # . restore registers
21619     5f/pop-to-edi
21620     5e/pop-to-esi
21621     5b/pop-to-ebx
21622     5a/pop-to-edx
21623     59/pop-to-ecx
21624     # . epilogue
21625     89/<- %esp 5/r32/ebp
21626     5d/pop-to-ebp
21627     c3/return
21628 
21629 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
21630     # . prologue
21631     55/push-ebp
21632     89/<- %ebp 4/r32/esp
21633     # . save registers
21634     51/push-ecx
21635     # var curr/ecx: (handle function) = functions
21636     8b/-> *(ebp+8) 1/r32/ecx
21637     {
21638       # if (curr == null) break
21639       81 7/subop/compare %ecx 0/imm32
21640       74/jump-if-= break/disp8
21641 #?       (write-buffered Stderr "iter\n")
21642 #?       (flush Stderr)
21643       # if match(stmt, curr) return curr
21644       {
21645         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
21646         3d/compare-eax-and 0/imm32/false
21647         74/jump-if-= break/disp8
21648         89/<- %eax 1/r32/ecx
21649         eb/jump $find-matching-function:end/disp8
21650       }
21651       # curr = curr->next
21652       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
21653       89/<- %ecx 0/r32/eax
21654       #
21655       eb/jump loop/disp8
21656     }
21657     # return null
21658     b8/copy-to-eax 0/imm32
21659 $find-matching-function:end:
21660     # . restore registers
21661     59/pop-to-ecx
21662     # . epilogue
21663     89/<- %esp 5/r32/ebp
21664     5d/pop-to-ebp
21665     c3/return
21666 
21667 # Just compare names; user-defined functions don't support overloading yet.
21668 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
21669     # . prologue
21670     55/push-ebp
21671     89/<- %ebp 4/r32/esp
21672     # . save registers
21673     51/push-ecx
21674     # return function->name == stmt->operation
21675     # ecx = lookup(stmt->operation)
21676     8b/-> *(ebp+8) 0/r32/eax
21677     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
21678     89/<- %ecx 0/r32/eax
21679     # eax = lookup(function->name)
21680     8b/-> *(ebp+0xc) 0/r32/eax
21681     (lookup *eax *(eax+4))  # Function-name Function-name => eax
21682     (string-equal? %eax %ecx)  # => eax
21683 $mu-stmt-matches-function?:end:
21684     # . restore registers
21685     59/pop-to-ecx
21686     # . epilogue
21687     89/<- %esp 5/r32/ebp
21688     5d/pop-to-ebp
21689     c3/return
21690 
21691 # Type-checking happens elsewhere. This method is for selecting between
21692 # primitives.
21693 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
21694     # . prologue
21695     55/push-ebp
21696     89/<- %ebp 4/r32/esp
21697     # . save registers
21698     51/push-ecx
21699     # var alit/ecx: boolean = is-literal-type?(a)
21700     (is-simple-mu-type? *(ebp+8) 0)  # => eax
21701     89/<- %ecx 0/r32/eax
21702     # var blit/eax: boolean = is-literal-type?(b)
21703     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
21704     # return alit == blit
21705     39/compare %eax 1/r32/ecx
21706     0f 94/set-byte-if-= %al
21707     81 4/subop/and %eax 0xff/imm32
21708 $subx-type-category-match?:end:
21709     # . restore registers
21710     59/pop-to-ecx
21711     # . epilogue
21712     89/<- %esp 5/r32/ebp
21713     5d/pop-to-ebp
21714     c3/return
21715 
21716 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
21717     # . prologue
21718     55/push-ebp
21719     89/<- %ebp 4/r32/esp
21720     # . save registers
21721     51/push-ecx
21722     # ecx = n
21723     8b/-> *(ebp+0xc) 1/r32/ecx
21724     # return (a->value == n)
21725     8b/-> *(ebp+8) 0/r32/eax
21726     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
21727     0f 94/set-byte-if-= %al
21728     81 4/subop/and %eax 0xff/imm32
21729 $is-simple-mu-type?:end:
21730     # . restore registers
21731     59/pop-to-ecx
21732     # . epilogue
21733     89/<- %esp 5/r32/ebp
21734     5d/pop-to-ebp
21735     c3/return
21736 
21737 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
21738     # . prologue
21739     55/push-ebp
21740     89/<- %ebp 4/r32/esp
21741     # eax = a
21742     8b/-> *(ebp+8) 0/r32/eax
21743     # if (!a->is-atom?) a = a->left
21744     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21745     {
21746       75/jump-if-!= break/disp8
21747       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21748     }
21749     # return (a->value == addr)
21750     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
21751     0f 94/set-byte-if-= %al
21752     81 4/subop/and %eax 0xff/imm32
21753 $is-mu-addr-type?:end:
21754     # . epilogue
21755     89/<- %esp 5/r32/ebp
21756     5d/pop-to-ebp
21757     c3/return
21758 
21759 is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
21760     # . prologue
21761     55/push-ebp
21762     89/<- %ebp 4/r32/esp
21763     # eax = a
21764     8b/-> *(ebp+8) 0/r32/eax
21765     # if (!a->is-atom?) a = a->left
21766     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21767     {
21768       75/jump-if-!= break/disp8
21769       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21770     }
21771     # return (a->value == array)
21772     81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
21773     0f 94/set-byte-if-= %al
21774     81 4/subop/and %eax 0xff/imm32
21775 $is-mu-array-type?:end:
21776     # . epilogue
21777     89/<- %esp 5/r32/ebp
21778     5d/pop-to-ebp
21779     c3/return
21780 
21781 is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
21782     # . prologue
21783     55/push-ebp
21784     89/<- %ebp 4/r32/esp
21785     # eax = a
21786     8b/-> *(ebp+8) 0/r32/eax
21787     # if (!a->is-atom?) a = a->left
21788     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
21789     {
21790       75/jump-if-!= break/disp8
21791       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
21792     }
21793     # return (a->value == stream)
21794     81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
21795     0f 94/set-byte-if-= %al
21796     81 4/subop/and %eax 0xff/imm32
21797 $is-mu-stream-type?:end:
21798     # . epilogue
21799     89/<- %esp 5/r32/ebp
21800     5d/pop-to-ebp
21801     c3/return
21802 
21803 test-emit-subx-stmt-primitive:
21804     # Primitive operation on a variable on the stack.
21805     #   increment foo
21806     # =>
21807     #   ff 0/subop/increment *(ebp-8)
21808     #
21809     # There's a variable on the var stack as follows:
21810     #   name: 'foo'
21811     #   type: int
21812     #   stack-offset: -8
21813     #
21814     # There's a primitive with this info:
21815     #   name: 'increment'
21816     #   inouts: int/mem
21817     #   value: 'ff 0/subop/increment'
21818     #
21819     # . prologue
21820     55/push-ebp
21821     89/<- %ebp 4/r32/esp
21822     # setup
21823     (clear-stream _test-output-stream)
21824     (clear-stream $_test-output-buffered-file->buffer)
21825     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
21826 $test-emit-subx-stmt-primitive:initialize-type:
21827     # var type/ecx: (payload type-tree) = int
21828     68/push 0/imm32/right:null
21829     68/push 0/imm32/right:null
21830     68/push 0/imm32/left:unused
21831     68/push 1/imm32/value:int
21832     68/push 1/imm32/is-atom?:true
21833     68/push 0x11/imm32/alloc-id:fake:payload
21834     89/<- %ecx 4/r32/esp
21835 $test-emit-subx-stmt-primitive:initialize-var:
21836     # var var-foo/ecx: (payload var) = var(type)
21837     68/push 0/imm32/no-register
21838     68/push 0/imm32/no-register
21839     68/push -8/imm32/stack-offset
21840     68/push 1/imm32/block-depth
21841     51/push-ecx/type
21842     68/push 0x11/imm32/alloc-id:fake
21843     68/push 0/imm32/name
21844     68/push 0/imm32/name
21845     68/push 0x11/imm32/alloc-id:fake:payload
21846     89/<- %ecx 4/r32/esp
21847 $test-emit-subx-stmt-primitive:initialize-var-name:
21848     # var-foo->name = "foo"
21849     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21850     (copy-array Heap "foo" %eax)
21851 $test-emit-subx-stmt-primitive:initialize-stmt-var:
21852     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
21853     68/push 0/imm32/is-deref:false
21854     68/push 0/imm32/next
21855     68/push 0/imm32/next
21856     51/push-ecx/var-foo
21857     68/push 0x11/imm32/alloc-id:fake
21858     68/push 0x11/imm32/alloc-id:fake:payload
21859     89/<- %ebx 4/r32/esp
21860 $test-emit-subx-stmt-primitive:initialize-stmt:
21861     # var stmt/esi: (addr statement)
21862     68/push 0/imm32/no-outputs
21863     68/push 0/imm32/no-outputs
21864     53/push-ebx/inouts
21865     68/push 0x11/imm32/alloc-id:fake
21866     68/push 0/imm32/operation
21867     68/push 0/imm32/operation
21868     68/push 1/imm32/tag
21869     89/<- %esi 4/r32/esp
21870 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
21871     # stmt->operation = "increment"
21872     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21873     (copy-array Heap "increment" %eax)
21874 $test-emit-subx-stmt-primitive:initialize-primitive:
21875     # var primitives/ebx: (addr primitive)
21876     68/push 0/imm32/next
21877     68/push 0/imm32/next
21878     68/push 0/imm32/output-is-write-only
21879     68/push 0/imm32/no-disp32
21880     68/push 0/imm32/no-imm8
21881     68/push 0/imm32/no-imm32
21882     68/push 0/imm32/no-r32
21883     68/push 1/imm32/rm32-is-first-inout
21884     68/push 0/imm32/subx-name
21885     68/push 0/imm32/subx-name
21886     68/push 0/imm32/no-outputs
21887     68/push 0/imm32/no-outputs
21888     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
21889     68/push 0x11/imm32/alloc-id:fake
21890     68/push 0/imm32/name
21891     68/push 0/imm32/name
21892     89/<- %ebx 4/r32/esp
21893 $test-emit-subx-stmt-primitive:initialize-primitive-name:
21894     # primitives->name = "increment"
21895     (copy-array Heap "increment" %ebx)  # Primitive-name
21896 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
21897     # primitives->subx-name = "ff 0/subop/increment"
21898     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
21899     (copy-array Heap "ff 0/subop/increment" %eax)
21900     # convert
21901     c7 0/subop/copy *Curr-block-depth 0/imm32
21902     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
21903     (flush _test-output-buffered-file)
21904 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
21910     # check output
21911     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
21912     # . epilogue
21913     89/<- %esp 5/r32/ebp
21914     5d/pop-to-ebp
21915     c3/return
21916 
21917 test-emit-subx-stmt-primitive-register:
21918     # Primitive operation on a variable in a register.
21919     #   foo <- increment
21920     # =>
21921     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
21922     #
21923     # There's a variable on the var stack as follows:
21924     #   name: 'foo'
21925     #   type: int
21926     #   register: 'eax'
21927     #
21928     # There's a primitive with this info:
21929     #   name: 'increment'
21930     #   out: int/reg
21931     #   value: 'ff 0/subop/increment'
21932     #
21933     # . prologue
21934     55/push-ebp
21935     89/<- %ebp 4/r32/esp
21936     # setup
21937     (clear-stream _test-output-stream)
21938     (clear-stream $_test-output-buffered-file->buffer)
21939 $test-emit-subx-stmt-primitive-register:initialize-type:
21940     # var type/ecx: (payload type-tree) = int
21941     68/push 0/imm32/right:null
21942     68/push 0/imm32/right:null
21943     68/push 0/imm32/left:unused
21944     68/push 1/imm32/value:int
21945     68/push 1/imm32/is-atom?:true
21946     68/push 0x11/imm32/alloc-id:fake:payload
21947     89/<- %ecx 4/r32/esp
21948 $test-emit-subx-stmt-primitive-register:initialize-var:
21949     # var var-foo/ecx: (payload var)
21950     68/push 0/imm32/register
21951     68/push 0/imm32/register
21952     68/push 0/imm32/no-stack-offset
21953     68/push 1/imm32/block-depth
21954     51/push-ecx
21955     68/push 0x11/imm32/alloc-id:fake
21956     68/push 0/imm32/name
21957     68/push 0/imm32/name
21958     68/push 0x11/imm32/alloc-id:fake:payload
21959     89/<- %ecx 4/r32/esp
21960 $test-emit-subx-stmt-primitive-register:initialize-var-name:
21961     # var-foo->name = "foo"
21962     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
21963     (copy-array Heap "foo" %eax)
21964 $test-emit-subx-stmt-primitive-register:initialize-var-register:
21965     # var-foo->register = "eax"
21966     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
21967     (copy-array Heap "eax" %eax)
21968 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
21969     # var operand/ebx: (payload stmt-var)
21970     68/push 0/imm32/is-deref:false
21971     68/push 0/imm32/next
21972     68/push 0/imm32/next
21973     51/push-ecx/var-foo
21974     68/push 0x11/imm32/alloc-id:fake
21975     68/push 0x11/imm32/alloc-id:fake:payload
21976     89/<- %ebx 4/r32/esp
21977 $test-emit-subx-stmt-primitive-register:initialize-stmt:
21978     # var stmt/esi: (addr statement)
21979     53/push-ebx/outputs
21980     68/push 0x11/imm32/alloc-id:fake
21981     68/push 0/imm32/no-inouts
21982     68/push 0/imm32/no-inouts
21983     68/push 0/imm32/operation
21984     68/push 0/imm32/operation
21985     68/push 1/imm32
21986     89/<- %esi 4/r32/esp
21987 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
21988     # stmt->operation = "increment"
21989     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
21990     (copy-array Heap "increment" %eax)
21991 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
21992     # var formal-var/ebx: (payload var)
21993     68/push 0/imm32/register
21994     68/push 0/imm32/register
21995     68/push 0/imm32/no-stack-offset
21996     68/push 1/imm32/block-depth
21997     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
21998     68/push 0x11/imm32/alloc-id:fake
21999     68/push 0/imm32/name
22000     68/push 0/imm32/name
22001     68/push 0x11/imm32/alloc-id:fake:payload
22002     89/<- %ebx 4/r32/esp
22003 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
22004     # formal-var->name = "dummy"
22005     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
22006     (copy-array Heap "dummy" %eax)
22007 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
22008     # formal-var->register = "*"
22009     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
22010     (copy-array Heap "*" %eax)  # Any-register
22011 $test-emit-subx-stmt-primitive-register:initialize-var-list:
22012     # var formal-outputs/ebx: (payload list var)
22013     68/push 0/imm32/next
22014     68/push 0/imm32/next
22015     53/push-ebx/formal-var
22016     68/push 0x11/imm32/alloc-id:fake
22017     68/push 0x11/imm32/alloc-id:fake:payload
22018     89/<- %ebx 4/r32/esp
22019 $test-emit-subx-stmt-primitive-register:initialize-primitive:
22020     # var primitives/ebx: (addr primitive)
22021     68/push 0/imm32/next
22022     68/push 0/imm32/next
22023     68/push 0/imm32/output-is-write-only
22024     68/push 0/imm32/no-disp32
22025     68/push 0/imm32/no-imm8
22026     68/push 0/imm32/no-imm32
22027     68/push 0/imm32/no-r32
22028     68/push 3/imm32/rm32-is-first-output
22029     68/push 0/imm32/subx-name
22030     68/push 0/imm32/subx-name
22031     53/push-ebx/outputs
22032     68/push 0x11/imm32/alloc-id:fake
22033     68/push 0/imm32/no-inouts
22034     68/push 0/imm32/no-inouts
22035     68/push 0/imm32/name
22036     68/push 0/imm32/name
22037     89/<- %ebx 4/r32/esp
22038 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
22039     # primitives->name = "increment"
22040     (copy-array Heap "increment" %ebx)  # Primitive-name
22041 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
22042     # primitives->subx-name = "ff 0/subop/increment"
22043     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
22044     (copy-array Heap "ff 0/subop/increment" %eax)
22045     # convert
22046     c7 0/subop/copy *Curr-block-depth 0/imm32
22047     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
22048     (flush _test-output-buffered-file)
22049 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22055     # check output
22056     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
22057     # . epilogue
22058     89/<- %esp 5/r32/ebp
22059     5d/pop-to-ebp
22060     c3/return
22061 
22062 test-emit-subx-stmt-select-primitive:
22063     # Select the right primitive between overloads.
22064     #   foo <- increment
22065     # =>
22066     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
22067     #
22068     # There's a variable on the var stack as follows:
22069     #   name: 'foo'
22070     #   type: int
22071     #   register: 'eax'
22072     #
22073     # There's two primitives, as follows:
22074     #   - name: 'increment'
22075     #     out: int/reg
22076     #     value: 'ff 0/subop/increment'
22077     #   - name: 'increment'
22078     #     inout: int/mem
22079     #     value: 'ff 0/subop/increment'
22080     #
22081     # . prologue
22082     55/push-ebp
22083     89/<- %ebp 4/r32/esp
22084     # setup
22085     (clear-stream _test-output-stream)
22086     (clear-stream $_test-output-buffered-file->buffer)
22087 $test-emit-subx-stmt-select-primitive:initialize-type:
22088     # var type/ecx: (payload type-tree) = int
22089     68/push 0/imm32/right:null
22090     68/push 0/imm32/right:null
22091     68/push 0/imm32/left:unused
22092     68/push 1/imm32/value:int
22093     68/push 1/imm32/is-atom?:true
22094     68/push 0x11/imm32/alloc-id:fake:payload
22095     89/<- %ecx 4/r32/esp
22096 $test-emit-subx-stmt-select-primitive:initialize-var:
22097     # var var-foo/ecx: (payload var)
22098     68/push 0/imm32/register
22099     68/push 0/imm32/register
22100     68/push 0/imm32/no-stack-offset
22101     68/push 1/imm32/block-depth
22102     51/push-ecx
22103     68/push 0x11/imm32/alloc-id:fake
22104     68/push 0/imm32/name
22105     68/push 0/imm32/name
22106     68/push 0x11/imm32/alloc-id:fake:payload
22107     89/<- %ecx 4/r32/esp
22108 $test-emit-subx-stmt-select-primitive:initialize-var-name:
22109     # var-foo->name = "foo"
22110     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22111     (copy-array Heap "foo" %eax)
22112 $test-emit-subx-stmt-select-primitive:initialize-var-register:
22113     # var-foo->register = "eax"
22114     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22115     (copy-array Heap "eax" %eax)
22116 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
22117     # var operand/ebx: (payload stmt-var)
22118     68/push 0/imm32/is-deref:false
22119     68/push 0/imm32/next
22120     68/push 0/imm32/next
22121     51/push-ecx/var-foo
22122     68/push 0x11/imm32/alloc-id:fake
22123     68/push 0x11/imm32/alloc-id:fake:payload
22124     89/<- %ebx 4/r32/esp
22125 $test-emit-subx-stmt-select-primitive:initialize-stmt:
22126     # var stmt/esi: (addr statement)
22127     53/push-ebx/outputs
22128     68/push 0x11/imm32/alloc-id:fake
22129     68/push 0/imm32/no-inouts
22130     68/push 0/imm32/no-inouts
22131     68/push 0/imm32/operation
22132     68/push 0/imm32/operation
22133     68/push 1/imm32
22134     89/<- %esi 4/r32/esp
22135 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
22136     # stmt->operation = "increment"
22137     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22138     (copy-array Heap "increment" %eax)
22139 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
22140     # var formal-var/ebx: (payload var)
22141     68/push 0/imm32/register
22142     68/push 0/imm32/register
22143     68/push 0/imm32/no-stack-offset
22144     68/push 1/imm32/block-depth
22145     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
22146     68/push 0x11/imm32/alloc-id:fake
22147     68/push 0/imm32/name
22148     68/push 0/imm32/name
22149     68/push 0x11/imm32/alloc-id:fake:payload
22150     89/<- %ebx 4/r32/esp
22151 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
22152     # formal-var->name = "dummy"
22153     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
22154     (copy-array Heap "dummy" %eax)
22155 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
22156     # formal-var->register = "*"
22157     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
22158     (copy-array Heap "*" %eax)  # Any-register
22159 $test-emit-subx-stmt-select-primitive:initialize-var-list:
22160     # var formal-outputs/ebx: (payload list var)
22161     68/push 0/imm32/next
22162     68/push 0/imm32/next
22163     53/push-ebx/formal-var
22164     68/push 0x11/imm32/alloc-id:fake
22165     68/push 0x11/imm32/alloc-id:fake:payload
22166     89/<- %ebx 4/r32/esp
22167 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
22168     # var primitive2/edi: (payload primitive)
22169     68/push 0/imm32/next
22170     68/push 0/imm32/next
22171     68/push 0/imm32/output-is-write-only
22172     68/push 0/imm32/no-disp32
22173     68/push 0/imm32/no-imm8
22174     68/push 0/imm32/no-imm32
22175     68/push 0/imm32/no-r32
22176     68/push 3/imm32/rm32-is-first-output
22177     68/push 0/imm32/subx-name
22178     68/push 0/imm32/subx-name
22179     53/push-ebx/outputs
22180     68/push 0x11/imm32/alloc-id:fake
22181     68/push 0/imm32/no-inouts
22182     68/push 0/imm32/no-inouts
22183     68/push 0/imm32/name
22184     68/push 0/imm32/name
22185     68/push 0x11/imm32/alloc-id:fake:payload
22186     89/<- %edi 4/r32/esp
22187 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
22188     # primitives->name = "increment"
22189     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
22190     (copy-array Heap "increment" %eax)
22191 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
22192     # primitives->subx-name = "ff 0/subop/increment"
22193     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
22194     (copy-array Heap "ff 0/subop/increment" %eax)
22195 $test-emit-subx-stmt-select-primitive:initialize-primitive:
22196     # var primitives/ebx: (addr primitive)
22197     57/push-edi
22198     68/push 0x11/imm32/alloc-id:fake
22199     68/push 0/imm32/output-is-write-only
22200     68/push 0/imm32/no-disp32
22201     68/push 0/imm32/no-imm8
22202     68/push 0/imm32/no-imm32
22203     68/push 0/imm32/no-r32
22204     68/push 1/imm32/rm32-is-first-inout
22205     68/push 0/imm32/subx-name
22206     68/push 0/imm32/subx-name
22207     68/push 0/imm32/no-outputs
22208     68/push 0/imm32/no-outputs
22209     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
22210     68/push 0x11/imm32/alloc-id:fake
22211     68/push 0/imm32/name
22212     68/push 0/imm32/name
22213     89/<- %ebx 4/r32/esp
22214 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
22215     # primitives->name = "increment"
22216     (copy-array Heap "increment" %ebx)  # Primitive-name
22217 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
22218     # primitives->subx-name = "ff 0/subop/increment"
22219     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
22220     (copy-array Heap "ff 0/subop/increment" %eax)
22221     # convert
22222     c7 0/subop/copy *Curr-block-depth 0/imm32
22223     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
22224     (flush _test-output-buffered-file)
22225 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22231     # check output
22232     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
22233     # . epilogue
22234     89/<- %esp 5/r32/ebp
22235     5d/pop-to-ebp
22236     c3/return
22237 
22238 test-emit-subx-stmt-select-primitive-2:
22239     # Select the right primitive between overloads.
22240     #   increment foo
22241     # =>
22242     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
22243     #
22244     # There's a variable on the var stack as follows:
22245     #   name: 'foo'
22246     #   type: int
22247     #   register: 'eax'
22248     #
22249     # There's two primitives, as follows:
22250     #   - name: 'increment'
22251     #     out: int/reg
22252     #     value: 'ff 0/subop/increment'
22253     #   - name: 'increment'
22254     #     inout: int/mem
22255     #     value: 'ff 0/subop/increment'
22256     #
22257     # . prologue
22258     55/push-ebp
22259     89/<- %ebp 4/r32/esp
22260     # setup
22261     (clear-stream _test-output-stream)
22262     (clear-stream $_test-output-buffered-file->buffer)
22263 $test-emit-subx-stmt-select-primitive-2:initialize-type:
22264     # var type/ecx: (payload type-tree) = int
22265     68/push 0/imm32/right:null
22266     68/push 0/imm32/right:null
22267     68/push 0/imm32/left:unused
22268     68/push 1/imm32/value:int
22269     68/push 1/imm32/is-atom?:true
22270     68/push 0x11/imm32/alloc-id:fake:payload
22271     89/<- %ecx 4/r32/esp
22272 $test-emit-subx-stmt-select-primitive-2:initialize-var:
22273     # var var-foo/ecx: (payload var)
22274     68/push 0/imm32/register
22275     68/push 0/imm32/register
22276     68/push 0/imm32/no-stack-offset
22277     68/push 1/imm32/block-depth
22278     51/push-ecx
22279     68/push 0x11/imm32/alloc-id:fake
22280     68/push 0/imm32/name
22281     68/push 0/imm32/name
22282     68/push 0x11/imm32/alloc-id:fake:payload
22283     89/<- %ecx 4/r32/esp
22284 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
22285     # var-foo->name = "foo"
22286     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22287     (copy-array Heap "foo" %eax)
22288 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
22289     # var-foo->register = "eax"
22290     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22291     (copy-array Heap "eax" %eax)
22292 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
22293     # var operand/ebx: (payload stmt-var)
22294     68/push 0/imm32/is-deref:false
22295     68/push 0/imm32/next
22296     68/push 0/imm32/next
22297     51/push-ecx/var-foo
22298     68/push 0x11/imm32/alloc-id:fake
22299     68/push 0x11/imm32/alloc-id:fake:payload
22300     89/<- %ebx 4/r32/esp
22301 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
22302     # var stmt/esi: (addr statement)
22303     68/push 0/imm32/no-outputs
22304     68/push 0/imm32/no-outputs
22305     53/push-ebx/inouts
22306     68/push 0x11/imm32/alloc-id:fake
22307     68/push 0/imm32/operation
22308     68/push 0/imm32/operation
22309     68/push 1/imm32
22310     89/<- %esi 4/r32/esp
22311 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
22312     # stmt->operation = "increment"
22313     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22314     (copy-array Heap "increment" %eax)
22315 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
22316     # var formal-var/ebx: (payload var)
22317     68/push 0/imm32/register
22318     68/push 0/imm32/register
22319     68/push 0/imm32/no-stack-offset
22320     68/push 1/imm32/block-depth
22321     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
22322     68/push 0x11/imm32/alloc-id:fake
22323     68/push 0/imm32/name
22324     68/push 0/imm32/name
22325     68/push 0x11/imm32/alloc-id:fake:payload
22326     89/<- %ebx 4/r32/esp
22327 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
22328     # formal-var->name = "dummy"
22329     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
22330     (copy-array Heap "dummy" %eax)
22331 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
22332     # formal-var->register = "*"
22333     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
22334     (copy-array Heap "*" %eax)  # Any-register
22335 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
22336     # var formal-outputs/ebx: (payload list stmt-var)
22337     68/push 0/imm32/next
22338     68/push 0/imm32/next
22339     53/push-ebx/formal-var
22340     68/push 0x11/imm32/alloc-id:fake
22341     68/push 0x11/imm32/alloc-id:fake:payload
22342     89/<- %ebx 4/r32/esp
22343 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
22344     # var primitive2/edi: (payload primitive)
22345     68/push 0/imm32/next
22346     68/push 0/imm32/next
22347     68/push 0/imm32/output-is-write-only
22348     68/push 0/imm32/no-disp32
22349     68/push 0/imm32/no-imm8
22350     68/push 0/imm32/no-imm32
22351     68/push 0/imm32/no-r32
22352     68/push 3/imm32/rm32-is-first-output
22353     68/push 0/imm32/subx-name
22354     68/push 0/imm32/subx-name
22355     53/push-ebx/outputs
22356     68/push 0x11/imm32/alloc-id:fake
22357     68/push 0/imm32/no-inouts
22358     68/push 0/imm32/no-inouts
22359     68/push 0/imm32/name
22360     68/push 0/imm32/name
22361     68/push 0x11/imm32/alloc-id:fake:payload
22362     89/<- %edi 4/r32/esp
22363 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
22364     # primitives->name = "increment"
22365     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
22366     (copy-array Heap "increment" %eax)
22367 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
22368     # primitives->subx-name = "ff 0/subop/increment"
22369     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
22370     (copy-array Heap "ff 0/subop/increment" %eax)
22371 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
22372     # var primitives/ebx: (addr primitive)
22373     57/push-edi
22374     68/push 0x11/imm32/alloc-id:fake
22375     68/push 0/imm32/output-is-write-only
22376     68/push 0/imm32/no-disp32
22377     68/push 0/imm32/no-imm8
22378     68/push 0/imm32/no-imm32
22379     68/push 0/imm32/no-r32
22380     68/push 1/imm32/rm32-is-first-inout
22381     68/push 0/imm32/subx-name
22382     68/push 0/imm32/subx-name
22383     68/push 0/imm32/no-outputs
22384     68/push 0/imm32/no-outputs
22385     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
22386     68/push 0x11/imm32/alloc-id:fake
22387     68/push 0/imm32/name
22388     68/push 0/imm32/name
22389     89/<- %ebx 4/r32/esp
22390 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
22391     # primitives->name = "increment"
22392     (copy-array Heap "increment" %ebx)  # Primitive-name
22393 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
22394     # primitives->subx-name = "ff 0/subop/increment"
22395     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
22396     (copy-array Heap "ff 0/subop/increment" %eax)
22397     # convert
22398     c7 0/subop/copy *Curr-block-depth 0/imm32
22399     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
22400     (flush _test-output-buffered-file)
22401 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22407     # check output
22408     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
22409     # . epilogue
22410     89/<- %esp 5/r32/ebp
22411     5d/pop-to-ebp
22412     c3/return
22413 
22414 test-increment-register:
22415     # Select the right register between overloads.
22416     #   foo <- increment
22417     # =>
22418     #   50/increment-eax
22419     #
22420     # There's a variable on the var stack as follows:
22421     #   name: 'foo'
22422     #   type: int
22423     #   register: 'eax'
22424     #
22425     # Primitives are the global definitions.
22426     #
22427     # . prologue
22428     55/push-ebp
22429     89/<- %ebp 4/r32/esp
22430     # setup
22431     (clear-stream _test-output-stream)
22432     (clear-stream $_test-output-buffered-file->buffer)
22433 $test-increment-register:initialize-type:
22434     # var type/ecx: (payload type-tree) = int
22435     68/push 0/imm32/right:null
22436     68/push 0/imm32/right:null
22437     68/push 0/imm32/left:unused
22438     68/push 1/imm32/value:int
22439     68/push 1/imm32/is-atom?:true
22440     68/push 0x11/imm32/alloc-id:fake:payload
22441     89/<- %ecx 4/r32/esp
22442 $test-increment-register:initialize-var:
22443     # var var-foo/ecx: (payload var)
22444     68/push 0/imm32/register
22445     68/push 0/imm32/register
22446     68/push 0/imm32/no-stack-offset
22447     68/push 1/imm32/block-depth
22448     51/push-ecx
22449     68/push 0x11/imm32/alloc-id:fake
22450     68/push 0/imm32/name
22451     68/push 0/imm32/name
22452     68/push 0x11/imm32/alloc-id:fake:payload
22453     89/<- %ecx 4/r32/esp
22454 $test-increment-register:initialize-var-name:
22455     # var-foo->name = "foo"
22456     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22457     (copy-array Heap "foo" %eax)
22458 $test-increment-register:initialize-var-register:
22459     # var-foo->register = "eax"
22460     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22461     (copy-array Heap "eax" %eax)
22462 $test-increment-register:initialize-stmt-var:
22463     # var operand/ebx: (payload stmt-var)
22464     68/push 0/imm32/is-deref:false
22465     68/push 0/imm32/next
22466     68/push 0/imm32/next
22467     51/push-ecx/var-foo
22468     68/push 0x11/imm32/alloc-id:fake
22469     68/push 0x11/imm32/alloc-id:fake:payload
22470     89/<- %ebx 4/r32/esp
22471 $test-increment-register:initialize-stmt:
22472     # var stmt/esi: (addr statement)
22473     53/push-ebx/outputs
22474     68/push 0x11/imm32/alloc-id:fake
22475     68/push 0/imm32/no-inouts
22476     68/push 0/imm32/no-inouts
22477     68/push 0/imm32/operation
22478     68/push 0/imm32/operation
22479     68/push 1/imm32
22480     89/<- %esi 4/r32/esp
22481 $test-increment-register:initialize-stmt-operation:
22482     # stmt->operation = "increment"
22483     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22484     (copy-array Heap "increment" %eax)
22485     # convert
22486     c7 0/subop/copy *Curr-block-depth 0/imm32
22487     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22488     (flush _test-output-buffered-file)
22489 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22495     # check output
22496     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
22497     # . epilogue
22498     89/<- %esp 5/r32/ebp
22499     5d/pop-to-ebp
22500     c3/return
22501 
22502 test-add-reg-to-reg:
22503     #   var1/reg <- add var2/reg
22504     # =>
22505     #   01/add-to %var1 var2
22506     #
22507     # . prologue
22508     55/push-ebp
22509     89/<- %ebp 4/r32/esp
22510     # setup
22511     (clear-stream _test-output-stream)
22512     (clear-stream $_test-output-buffered-file->buffer)
22513 $test-add-reg-to-reg:initialize-type:
22514     # var type/ecx: (payload type-tree) = int
22515     68/push 0/imm32/right:null
22516     68/push 0/imm32/right:null
22517     68/push 0/imm32/left:unused
22518     68/push 1/imm32/value:int
22519     68/push 1/imm32/is-atom?:true
22520     68/push 0x11/imm32/alloc-id:fake:payload
22521     89/<- %ecx 4/r32/esp
22522 $test-add-reg-to-reg:initialize-var1:
22523     # var var1/ecx: (payload var)
22524     68/push 0/imm32/register
22525     68/push 0/imm32/register
22526     68/push 0/imm32/no-stack-offset
22527     68/push 1/imm32/block-depth
22528     51/push-ecx
22529     68/push 0x11/imm32/alloc-id:fake
22530     68/push 0/imm32/name
22531     68/push 0/imm32/name
22532     68/push 0x11/imm32/alloc-id:fake:payload
22533     89/<- %ecx 4/r32/esp
22534 $test-add-reg-to-reg:initialize-var1-name:
22535     # var1->name = "var1"
22536     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22537     (copy-array Heap "var1" %eax)
22538 $test-add-reg-to-reg:initialize-var1-register:
22539     # var1->register = "eax"
22540     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22541     (copy-array Heap "eax" %eax)
22542 $test-add-reg-to-reg:initialize-var2:
22543     # var var2/edx: (payload var)
22544     68/push 0/imm32/register
22545     68/push 0/imm32/register
22546     68/push 0/imm32/no-stack-offset
22547     68/push 1/imm32/block-depth
22548     ff 6/subop/push *(ecx+0x10)
22549     68/push 0x11/imm32/alloc-id:fake
22550     68/push 0/imm32/name
22551     68/push 0/imm32/name
22552     68/push 0x11/imm32/alloc-id:fake:payload
22553     89/<- %edx 4/r32/esp
22554 $test-add-reg-to-reg:initialize-var2-name:
22555     # var2->name = "var2"
22556     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22557     (copy-array Heap "var2" %eax)
22558 $test-add-reg-to-reg:initialize-var2-register:
22559     # var2->register = "ecx"
22560     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22561     (copy-array Heap "ecx" %eax)
22562 $test-add-reg-to-reg:initialize-inouts:
22563     # var inouts/esi: (payload stmt-var) = [var2]
22564     68/push 0/imm32/is-deref:false
22565     68/push 0/imm32/next
22566     68/push 0/imm32/next
22567     52/push-edx/var2
22568     68/push 0x11/imm32/alloc-id:fake
22569     68/push 0x11/imm32/alloc-id:fake:payload
22570     89/<- %esi 4/r32/esp
22571 $test-add-reg-to-reg:initialize-outputs:
22572     # var outputs/edi: (payload stmt-var) = [var1]
22573     68/push 0/imm32/is-deref:false
22574     68/push 0/imm32/next
22575     68/push 0/imm32/next
22576     51/push-ecx/var1
22577     68/push 0x11/imm32/alloc-id:fake
22578     68/push 0x11/imm32/alloc-id:fake:payload
22579     89/<- %edi 4/r32/esp
22580 $test-add-reg-to-reg:initialize-stmt:
22581     # var stmt/esi: (addr statement)
22582     68/push 0/imm32/next
22583     68/push 0/imm32/next
22584     57/push-edi/outputs
22585     68/push 0x11/imm32/alloc-id:fake
22586     56/push-esi/inouts
22587     68/push 0x11/imm32/alloc-id:fake
22588     68/push 0/imm32/operation
22589     68/push 0/imm32/operation
22590     68/push 1/imm32/tag:stmt1
22591     89/<- %esi 4/r32/esp
22592 $test-add-reg-to-reg:initialize-stmt-operation:
22593     # stmt->operation = "add"
22594     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22595     (copy-array Heap "add" %eax)
22596     # convert
22597     c7 0/subop/copy *Curr-block-depth 0/imm32
22598     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22599     (flush _test-output-buffered-file)
22600 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22606     # check output
22607     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
22608     # . epilogue
22609     89/<- %esp 5/r32/ebp
22610     5d/pop-to-ebp
22611     c3/return
22612 
22613 test-add-reg-to-mem:
22614     #   add-to var1 var2/reg
22615     # =>
22616     #   01/add-to *(ebp+__) var2
22617     #
22618     # . prologue
22619     55/push-ebp
22620     89/<- %ebp 4/r32/esp
22621     # setup
22622     (clear-stream _test-output-stream)
22623     (clear-stream $_test-output-buffered-file->buffer)
22624 $test-add-reg-to-mem:initialize-type:
22625     # var type/ecx: (payload type-tree) = int
22626     68/push 0/imm32/right:null
22627     68/push 0/imm32/right:null
22628     68/push 0/imm32/left:unused
22629     68/push 1/imm32/value:int
22630     68/push 1/imm32/is-atom?:true
22631     68/push 0x11/imm32/alloc-id:fake:payload
22632     89/<- %ecx 4/r32/esp
22633 $test-add-reg-to-mem:initialize-var1:
22634     # var var1/ecx: (payload var)
22635     68/push 0/imm32/register
22636     68/push 0/imm32/register
22637     68/push 8/imm32/stack-offset
22638     68/push 1/imm32/block-depth
22639     51/push-ecx
22640     68/push 0x11/imm32/alloc-id:fake
22641     68/push 0/imm32/name
22642     68/push 0/imm32/name
22643     68/push 0x11/imm32/alloc-id:fake:payload
22644     89/<- %ecx 4/r32/esp
22645 $test-add-reg-to-mem:initialize-var1-name:
22646     # var1->name = "var1"
22647     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22648     (copy-array Heap "var1" %eax)
22649 $test-add-reg-to-mem:initialize-var2:
22650     # var var2/edx: (payload var)
22651     68/push 0/imm32/register
22652     68/push 0/imm32/register
22653     68/push 0/imm32/no-stack-offset
22654     68/push 1/imm32/block-depth
22655     ff 6/subop/push *(ecx+0x10)
22656     68/push 0x11/imm32/alloc-id:fake
22657     68/push 0/imm32/name
22658     68/push 0/imm32/name
22659     68/push 0x11/imm32/alloc-id:fake:payload
22660     89/<- %edx 4/r32/esp
22661 $test-add-reg-to-mem:initialize-var2-name:
22662     # var2->name = "var2"
22663     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22664     (copy-array Heap "var2" %eax)
22665 $test-add-reg-to-mem:initialize-var2-register:
22666     # var2->register = "ecx"
22667     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
22668     (copy-array Heap "ecx" %eax)
22669 $test-add-reg-to-mem:initialize-inouts:
22670     # var inouts/esi: (payload stmt-var) = [var2]
22671     68/push 0/imm32/is-deref:false
22672     68/push 0/imm32/next
22673     68/push 0/imm32/next
22674     52/push-edx/var2
22675     68/push 0x11/imm32/alloc-id:fake
22676     68/push 0x11/imm32/alloc-id:fake:payload
22677     89/<- %esi 4/r32/esp
22678     # inouts = [var1, var2]
22679     68/push 0/imm32/is-deref:false
22680     56/push-esi/next
22681     68/push 0x11/imm32/alloc-id:fake
22682     51/push-ecx/var1
22683     68/push 0x11/imm32/alloc-id:fake
22684     68/push 0x11/imm32/alloc-id:fake:payload
22685     89/<- %esi 4/r32/esp
22686 $test-add-reg-to-mem:initialize-stmt:
22687     # var stmt/esi: (addr statement)
22688     68/push 0/imm32/next
22689     68/push 0/imm32/next
22690     68/push 0/imm32/outputs
22691     68/push 0/imm32/outputs
22692     56/push-esi/inouts
22693     68/push 0x11/imm32/alloc-id:fake
22694     68/push 0/imm32/operation
22695     68/push 0/imm32/operation
22696     68/push 1/imm32/tag:stmt1
22697     89/<- %esi 4/r32/esp
22698 $test-add-reg-to-mem:initialize-stmt-operation:
22699     # stmt->operation = "add-to"
22700     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22701     (copy-array Heap "add-to" %eax)
22702     # convert
22703     c7 0/subop/copy *Curr-block-depth 0/imm32
22704     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22705     (flush _test-output-buffered-file)
22706 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22712     # check output
22713     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
22714     # . epilogue
22715     89/<- %esp 5/r32/ebp
22716     5d/pop-to-ebp
22717     c3/return
22718 
22719 test-add-mem-to-reg:
22720     #   var1/reg <- add var2
22721     # =>
22722     #   03/add *(ebp+__) var1
22723     #
22724     # . prologue
22725     55/push-ebp
22726     89/<- %ebp 4/r32/esp
22727     # setup
22728     (clear-stream _test-output-stream)
22729     (clear-stream $_test-output-buffered-file->buffer)
22730 $test-add-mem-to-reg:initialize-type:
22731     # var type/ecx: (payload type-tree) = int
22732     68/push 0/imm32/right:null
22733     68/push 0/imm32/right:null
22734     68/push 0/imm32/left:unused
22735     68/push 1/imm32/value:int
22736     68/push 1/imm32/is-atom?:true
22737     68/push 0x11/imm32/alloc-id:fake:payload
22738     89/<- %ecx 4/r32/esp
22739 $test-add-mem-to-reg:initialize-var:
22740     # var var1/ecx: (payload var)
22741     68/push 0/imm32/register
22742     68/push 0/imm32/register
22743     68/push 0/imm32/no-stack-offset
22744     68/push 1/imm32/block-depth
22745     51/push-ecx
22746     68/push 0x11/imm32/alloc-id:fake
22747     68/push 0/imm32/name
22748     68/push 0/imm32/name
22749     68/push 0x11/imm32/alloc-id:fake:payload
22750     89/<- %ecx 4/r32/esp
22751 $test-add-mem-to-reg:initialize-var-name:
22752     # var1->name = "foo"
22753     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22754     (copy-array Heap "var1" %eax)
22755 $test-add-mem-to-reg:initialize-var-register:
22756     # var1->register = "eax"
22757     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22758     (copy-array Heap "eax" %eax)
22759 $test-add-mem-to-reg:initialize-var2:
22760     # var var2/edx: (payload var)
22761     68/push 0/imm32/register
22762     68/push 0/imm32/register
22763     68/push 8/imm32/stack-offset
22764     68/push 1/imm32/block-depth
22765     ff 6/subop/push *(ecx+0x10)
22766     68/push 0x11/imm32/alloc-id:fake
22767     68/push 0/imm32/name
22768     68/push 0/imm32/name
22769     68/push 0x11/imm32/alloc-id:fake:payload
22770     89/<- %edx 4/r32/esp
22771 $test-add-mem-to-reg:initialize-var2-name:
22772     # var2->name = "var2"
22773     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22774     (copy-array Heap "var2" %eax)
22775 $test-add-mem-to-reg:initialize-inouts:
22776     # var inouts/esi: (payload stmt-var) = [var2]
22777     68/push 0/imm32/is-deref:false
22778     68/push 0/imm32/next
22779     68/push 0/imm32/next
22780     52/push-edx/var2
22781     68/push 0x11/imm32/alloc-id:fake
22782     68/push 0x11/imm32/alloc-id:fake:payload
22783     89/<- %esi 4/r32/esp
22784 $test-add-mem-to-reg:initialize-outputs:
22785     # var outputs/edi: (payload stmt-var) = [var1]
22786     68/push 0/imm32/is-deref:false
22787     68/push 0/imm32/next
22788     68/push 0/imm32/next
22789     51/push-ecx/var1
22790     68/push 0x11/imm32/alloc-id:fake
22791     68/push 0x11/imm32/alloc-id:fake:payload
22792     89/<- %edi 4/r32/esp
22793 $test-add-mem-to-reg:initialize-stmt:
22794     # var stmt/esi: (addr statement)
22795     68/push 0/imm32/next
22796     68/push 0/imm32/next
22797     57/push-edi/outputs
22798     68/push 0x11/imm32/alloc-id:fake
22799     56/push-esi/inouts
22800     68/push 0x11/imm32/alloc-id:fake
22801     68/push 0/imm32/operation
22802     68/push 0/imm32/operation
22803     68/push 1/imm32/tag:stmt1
22804     89/<- %esi 4/r32/esp
22805 $test-add-mem-to-reg:initialize-stmt-operation:
22806     # stmt->operation = "add"
22807     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22808     (copy-array Heap "add" %eax)
22809     # convert
22810     c7 0/subop/copy *Curr-block-depth 0/imm32
22811     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22812     (flush _test-output-buffered-file)
22813 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22819     # check output
22820     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
22821     # . epilogue
22822     89/<- %esp 5/r32/ebp
22823     5d/pop-to-ebp
22824     c3/return
22825 
22826 test-add-literal-to-eax:
22827     #   var1/eax <- add 0x34
22828     # =>
22829     #   05/add-to-eax 0x34/imm32
22830     #
22831     # . prologue
22832     55/push-ebp
22833     89/<- %ebp 4/r32/esp
22834     # setup
22835     (clear-stream _test-output-stream)
22836     (clear-stream $_test-output-buffered-file->buffer)
22837 $test-add-literal-to-eax:initialize-var-type:
22838     # var type/ecx: (payload type-tree) = int
22839     68/push 0/imm32/right:null
22840     68/push 0/imm32/right:null
22841     68/push 0/imm32/left:unused
22842     68/push 1/imm32/value:int
22843     68/push 1/imm32/is-atom?:true
22844     68/push 0x11/imm32/alloc-id:fake:payload
22845     89/<- %ecx 4/r32/esp
22846 $test-add-literal-to-eax:initialize-var:
22847     # var v/ecx: (payload var)
22848     68/push 0/imm32/register
22849     68/push 0/imm32/register
22850     68/push 0/imm32/no-stack-offset
22851     68/push 1/imm32/block-depth
22852     51/push-ecx
22853     68/push 0x11/imm32/alloc-id:fake
22854     68/push 0/imm32/name
22855     68/push 0/imm32/name
22856     68/push 0x11/imm32/alloc-id:fake:payload
22857     89/<- %ecx 4/r32/esp
22858 $test-add-literal-to-eax:initialize-var-name:
22859     # v->name = "v"
22860     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22861     (copy-array Heap "v" %eax)
22862 $test-add-literal-to-eax:initialize-var-register:
22863     # v->register = "eax"
22864     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22865     (copy-array Heap "eax" %eax)
22866 $test-add-literal-to-eax:initialize-literal-type:
22867     # var type/edx: (payload type-tree) = literal
22868     68/push 0/imm32/right:null
22869     68/push 0/imm32/right:null
22870     68/push 0/imm32/left:unused
22871     68/push 0/imm32/value:literal
22872     68/push 1/imm32/is-atom?:true
22873     68/push 0x11/imm32/alloc-id:fake:payload
22874     89/<- %edx 4/r32/esp
22875 $test-add-literal-to-eax:initialize-literal:
22876     # var l/edx: (payload var)
22877     68/push 0/imm32/register
22878     68/push 0/imm32/register
22879     68/push 0/imm32/no-stack-offset
22880     68/push 1/imm32/block-depth
22881     52/push-edx
22882     68/push 0x11/imm32/alloc-id:fake
22883     68/push 0/imm32/name
22884     68/push 0/imm32/name
22885     68/push 0x11/imm32/alloc-id:fake:payload
22886     89/<- %edx 4/r32/esp
22887 $test-add-literal-to-eax:initialize-literal-value:
22888     # l->name = "0x34"
22889     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
22890     (copy-array Heap "0x34" %eax)
22891 $test-add-literal-to-eax:initialize-inouts:
22892     # var inouts/esi: (payload stmt-var) = [l]
22893     68/push 0/imm32/is-deref:false
22894     68/push 0/imm32/next
22895     68/push 0/imm32/next
22896     52/push-edx/l
22897     68/push 0x11/imm32/alloc-id:fake
22898     68/push 0x11/imm32/alloc-id:fake:payload
22899     89/<- %esi 4/r32/esp
22900 $test-add-literal-to-eax:initialize-outputs:
22901     # var outputs/edi: (payload stmt-var) = [v]
22902     68/push 0/imm32/is-deref:false
22903     68/push 0/imm32/next
22904     68/push 0/imm32/next
22905     51/push-ecx/v
22906     68/push 0x11/imm32/alloc-id:fake
22907     68/push 0x11/imm32/alloc-id:fake:payload
22908     89/<- %edi 4/r32/esp
22909 $test-add-literal-to-eax:initialize-stmt:
22910     # var stmt/esi: (addr statement)
22911     68/push 0/imm32/next
22912     68/push 0/imm32/next
22913     57/push-edi/outputs
22914     68/push 0x11/imm32/alloc-id:fake
22915     56/push-esi/inouts
22916     68/push 0x11/imm32/alloc-id:fake
22917     68/push 0/imm32/operation
22918     68/push 0/imm32/operation
22919     68/push 1/imm32/tag:stmt1
22920     89/<- %esi 4/r32/esp
22921 $test-add-literal-to-eax:initialize-stmt-operation:
22922     # stmt->operation = "add"
22923     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
22924     (copy-array Heap "add" %eax)
22925     # convert
22926     c7 0/subop/copy *Curr-block-depth 0/imm32
22927     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
22928     (flush _test-output-buffered-file)
22929 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
22935     # check output
22936     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
22937     # . epilogue
22938     89/<- %esp 5/r32/ebp
22939     5d/pop-to-ebp
22940     c3/return
22941 
22942 test-add-literal-to-reg:
22943     #   var1/ecx <- add 0x34
22944     # =>
22945     #   81 0/subop/add %ecx 0x34/imm32
22946     #
22947     # . prologue
22948     55/push-ebp
22949     89/<- %ebp 4/r32/esp
22950     # setup
22951     (clear-stream _test-output-stream)
22952     (clear-stream $_test-output-buffered-file->buffer)
22953 $test-add-literal-to-reg:initialize-var-type:
22954     # var type/ecx: (payload type-tree) = int
22955     68/push 0/imm32/right:null
22956     68/push 0/imm32/right:null
22957     68/push 0/imm32/left:unused
22958     68/push 1/imm32/value:int
22959     68/push 1/imm32/is-atom?:true
22960     68/push 0x11/imm32/alloc-id:fake:payload
22961     89/<- %ecx 4/r32/esp
22962 $test-add-literal-to-reg:initialize-var:
22963     # var v/ecx: (payload var)
22964     68/push 0/imm32/register
22965     68/push 0/imm32/register
22966     68/push 0/imm32/no-stack-offset
22967     68/push 1/imm32/block-depth
22968     51/push-ecx
22969     68/push 0x11/imm32/alloc-id:fake
22970     68/push 0/imm32/name
22971     68/push 0/imm32/name
22972     68/push 0x11/imm32/alloc-id:fake:payload
22973     89/<- %ecx 4/r32/esp
22974 $test-add-literal-to-reg:initialize-var-name:
22975     # v->name = "v"
22976     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
22977     (copy-array Heap "v" %eax)
22978 $test-add-literal-to-reg:initialize-var-register:
22979     # v->register = "ecx"
22980     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
22981     (copy-array Heap "ecx" %eax)
22982 $test-add-literal-to-reg:initialize-literal-type:
22983     # var type/edx: (payload type-tree) = literal
22984     68/push 0/imm32/right:null
22985     68/push 0/imm32/right:null
22986     68/push 0/imm32/left:unused
22987     68/push 0/imm32/value:literal
22988     68/push 1/imm32/is-atom?:true
22989     68/push 0x11/imm32/alloc-id:fake:payload
22990     89/<- %edx 4/r32/esp
22991 $test-add-literal-to-reg:initialize-literal:
22992     # var l/edx: (payload var)
22993     68/push 0/imm32/register
22994     68/push 0/imm32/register
22995     68/push 0/imm32/no-stack-offset
22996     68/push 1/imm32/block-depth
22997     52/push-edx
22998     68/push 0x11/imm32/alloc-id:fake
22999     68/push 0/imm32/name
23000     68/push 0/imm32/name
23001     68/push 0x11/imm32/alloc-id:fake:payload
23002     89/<- %edx 4/r32/esp
23003 $test-add-literal-to-reg:initialize-literal-value:
23004     # l->name = "0x34"
23005     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23006     (copy-array Heap "0x34" %eax)
23007 $test-add-literal-to-reg:initialize-inouts:
23008     # var inouts/esi: (payload stmt-var) = [l]
23009     68/push 0/imm32/is-deref:false
23010     68/push 0/imm32/next
23011     68/push 0/imm32/next
23012     52/push-edx/l
23013     68/push 0x11/imm32/alloc-id:fake
23014     68/push 0x11/imm32/alloc-id:fake:payload
23015     89/<- %esi 4/r32/esp
23016 $test-add-literal-to-reg:initialize-outputs:
23017     # var outputs/edi: (payload stmt-var) = [v]
23018     68/push 0/imm32/is-deref:false
23019     68/push 0/imm32/next
23020     68/push 0/imm32/next
23021     51/push-ecx/v
23022     68/push 0x11/imm32/alloc-id:fake
23023     68/push 0x11/imm32/alloc-id:fake:payload
23024     89/<- %edi 4/r32/esp
23025 $test-add-literal-to-reg:initialize-stmt:
23026     # var stmt/esi: (addr statement)
23027     68/push 0/imm32/next
23028     68/push 0/imm32/next
23029     57/push-edi/outputs
23030     68/push 0x11/imm32/alloc-id:fake
23031     56/push-esi/inouts
23032     68/push 0x11/imm32/alloc-id:fake
23033     68/push 0/imm32/operation
23034     68/push 0/imm32/operation
23035     68/push 1/imm32/tag:stmt1
23036     89/<- %esi 4/r32/esp
23037 $test-add-literal-to-reg:initialize-stmt-operation:
23038     # stmt->operation = "add"
23039     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23040     (copy-array Heap "add" %eax)
23041     # convert
23042     c7 0/subop/copy *Curr-block-depth 0/imm32
23043     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23044     (flush _test-output-buffered-file)
23045 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23051     # check output
23052     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
23053     # . epilogue
23054     89/<- %esp 5/r32/ebp
23055     5d/pop-to-ebp
23056     c3/return
23057 
23058 test-add-literal-to-mem:
23059     #   add-to var1, 0x34
23060     # =>
23061     #   81 0/subop/add %eax 0x34/imm32
23062     #
23063     # . prologue
23064     55/push-ebp
23065     89/<- %ebp 4/r32/esp
23066     # setup
23067     (clear-stream _test-output-stream)
23068     (clear-stream $_test-output-buffered-file->buffer)
23069 $test-add-literal-to-mem:initialize-type:
23070     # var type/ecx: (payload type-tree) = int
23071     68/push 0/imm32/right:null
23072     68/push 0/imm32/right:null
23073     68/push 0/imm32/left:unused
23074     68/push 1/imm32/value:int
23075     68/push 1/imm32/is-atom?:true
23076     68/push 0x11/imm32/alloc-id:fake:payload
23077     89/<- %ecx 4/r32/esp
23078 $test-add-literal-to-mem:initialize-var1:
23079     # var var1/ecx: (payload var)
23080     68/push 0/imm32/register
23081     68/push 0/imm32/register
23082     68/push 8/imm32/stack-offset
23083     68/push 1/imm32/block-depth
23084     51/push-ecx
23085     68/push 0x11/imm32/alloc-id:fake
23086     68/push 0/imm32/name
23087     68/push 0/imm32/name
23088     68/push 0x11/imm32/alloc-id:fake:payload
23089     89/<- %ecx 4/r32/esp
23090 $test-add-literal-to-mem:initialize-var1-name:
23091     # var1->name = "var1"
23092     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23093     (copy-array Heap "var1" %eax)
23094 $test-add-literal-to-mem:initialize-literal-type:
23095     # var type/edx: (payload type-tree) = literal
23096     68/push 0/imm32/right:null
23097     68/push 0/imm32/right:null
23098     68/push 0/imm32/left:unused
23099     68/push 0/imm32/value:literal
23100     68/push 1/imm32/is-atom?:true
23101     68/push 0x11/imm32/alloc-id:fake:payload
23102     89/<- %edx 4/r32/esp
23103 $test-add-literal-to-mem:initialize-literal:
23104     # var l/edx: (payload var)
23105     68/push 0/imm32/register
23106     68/push 0/imm32/register
23107     68/push 0/imm32/no-stack-offset
23108     68/push 1/imm32/block-depth
23109     52/push-edx
23110     68/push 0x11/imm32/alloc-id:fake
23111     68/push 0/imm32/name
23112     68/push 0/imm32/name
23113     68/push 0x11/imm32/alloc-id:fake:payload
23114     89/<- %edx 4/r32/esp
23115 $test-add-literal-to-mem:initialize-literal-value:
23116     # l->name = "0x34"
23117     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23118     (copy-array Heap "0x34" %eax)
23119 $test-add-literal-to-mem:initialize-inouts:
23120     # var inouts/esi: (payload stmt-var) = [l]
23121     68/push 0/imm32/is-deref:false
23122     68/push 0/imm32/next
23123     68/push 0/imm32/next
23124     52/push-edx/l
23125     68/push 0x11/imm32/alloc-id:fake
23126     68/push 0x11/imm32/alloc-id:fake:payload
23127     89/<- %esi 4/r32/esp
23128     # var inouts = (handle stmt-var) = [var1, var2]
23129     68/push 0/imm32/is-deref:false
23130     56/push-esi/next
23131     68/push 0x11/imm32/alloc-id:fake
23132     51/push-ecx/var1
23133     68/push 0x11/imm32/alloc-id:fake
23134     68/push 0x11/imm32/alloc-id:fake:payload
23135     89/<- %esi 4/r32/esp
23136 $test-add-literal-to-mem:initialize-stmt:
23137     # var stmt/esi: (addr statement)
23138     68/push 0/imm32/next
23139     68/push 0/imm32/next
23140     68/push 0/imm32/outputs
23141     68/push 0/imm32/outputs
23142     56/push-esi/inouts
23143     68/push 0x11/imm32/alloc-id:fake
23144     68/push 0/imm32/operation
23145     68/push 0/imm32/operation
23146     68/push 1/imm32/tag:stmt1
23147     89/<- %esi 4/r32/esp
23148 $test-add-literal-to-mem:initialize-stmt-operation:
23149     # stmt->operation = "add-to"
23150     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23151     (copy-array Heap "add-to" %eax)
23152     # convert
23153     c7 0/subop/copy *Curr-block-depth 0/imm32
23154     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23155     (flush _test-output-buffered-file)
23156 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23162     # check output
23163     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
23164     # . epilogue
23165     89/<- %esp 5/r32/ebp
23166     5d/pop-to-ebp
23167     c3/return
23168 
23169 test-shift-reg-by-literal:
23170     #   var1/ecx <- shift-left 2
23171     # =>
23172     #   c1/shift 4/subop/left %ecx 2/imm8
23173     #
23174     # . prologue
23175     55/push-ebp
23176     89/<- %ebp 4/r32/esp
23177     # setup
23178     (clear-stream _test-output-stream)
23179     (clear-stream $_test-output-buffered-file->buffer)
23180 $test-shift-reg-by-literal:initialize-var-type:
23181     # var type/ecx: (payload type-tree) = int
23182     68/push 0/imm32/right:null
23183     68/push 0/imm32/right:null
23184     68/push 0/imm32/left:unused
23185     68/push 1/imm32/value:int
23186     68/push 1/imm32/is-atom?:true
23187     68/push 0x11/imm32/alloc-id:fake:payload
23188     89/<- %ecx 4/r32/esp
23189 $test-shift-reg-by-literal:initialize-var:
23190     # var v/ecx: (payload var)
23191     68/push 0/imm32/register
23192     68/push 0/imm32/register
23193     68/push 0/imm32/no-stack-offset
23194     68/push 1/imm32/block-depth
23195     51/push-ecx
23196     68/push 0x11/imm32/alloc-id:fake
23197     68/push 0/imm32/name
23198     68/push 0/imm32/name
23199     68/push 0x11/imm32/alloc-id:fake:payload
23200     89/<- %ecx 4/r32/esp
23201 $test-shift-reg-by-literal:initialize-var-name:
23202     # v->name = "v"
23203     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23204     (copy-array Heap "v" %eax)
23205 $test-shift-reg-by-literal:initialize-var-register:
23206     # v->register = "ecx"
23207     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23208     (copy-array Heap "ecx" %eax)
23209 $test-shift-reg-by-literal:initialize-literal-type:
23210     # var type/edx: (payload type-tree) = literal
23211     68/push 0/imm32/right:null
23212     68/push 0/imm32/right:null
23213     68/push 0/imm32/left:unused
23214     68/push 0/imm32/value:literal
23215     68/push 1/imm32/is-atom?:true
23216     68/push 0x11/imm32/alloc-id:fake:payload
23217     89/<- %edx 4/r32/esp
23218 $test-shift-reg-by-literal:initialize-literal:
23219     # var l/edx: (payload var)
23220     68/push 0/imm32/register
23221     68/push 0/imm32/register
23222     68/push 0/imm32/no-stack-offset
23223     68/push 1/imm32/block-depth
23224     52/push-edx
23225     68/push 0x11/imm32/alloc-id:fake
23226     68/push 0/imm32/name
23227     68/push 0/imm32/name
23228     68/push 0x11/imm32/alloc-id:fake:payload
23229     89/<- %edx 4/r32/esp
23230 $test-shift-reg-by-literal:initialize-literal-value:
23231     # l->name = "2"
23232     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23233     (copy-array Heap "2" %eax)
23234 $test-shift-reg-by-literal:initialize-inouts:
23235     # var inouts/esi: (payload stmt-var) = [l]
23236     68/push 0/imm32/is-deref:false
23237     68/push 0/imm32/next
23238     68/push 0/imm32/next
23239     52/push-edx/l
23240     68/push 0x11/imm32/alloc-id:fake
23241     68/push 0x11/imm32/alloc-id:fake:payload
23242     89/<- %esi 4/r32/esp
23243 $test-shift-reg-by-literal:initialize-outputs:
23244     # var outputs/edi: (payload stmt-var) = [v]
23245     68/push 0/imm32/is-deref:false
23246     68/push 0/imm32/next
23247     68/push 0/imm32/next
23248     51/push-ecx/v
23249     68/push 0x11/imm32/alloc-id:fake
23250     68/push 0x11/imm32/alloc-id:fake:payload
23251     89/<- %edi 4/r32/esp
23252 $test-shift-reg-by-literal:initialize-stmt:
23253     # var stmt/esi: (addr statement)
23254     68/push 0/imm32/next
23255     68/push 0/imm32/next
23256     57/push-edi/outputs
23257     68/push 0x11/imm32/alloc-id:fake
23258     56/push-esi/inouts
23259     68/push 0x11/imm32/alloc-id:fake
23260     68/push 0/imm32/operation
23261     68/push 0/imm32/operation
23262     68/push 1/imm32/tag:stmt1
23263     89/<- %esi 4/r32/esp
23264 $test-shift-reg-by-literal:initialize-stmt-operation:
23265     # stmt->operation = "shift-left"
23266     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23267     (copy-array Heap "shift-left" %eax)
23268     # convert
23269     c7 0/subop/copy *Curr-block-depth 0/imm32
23270     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23271     (flush _test-output-buffered-file)
23272 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23278     # check output
23279     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
23280     # . epilogue
23281     89/<- %esp 5/r32/ebp
23282     5d/pop-to-ebp
23283     c3/return
23284 
23285 test-shift-mem-by-literal:
23286     #   shift-left var 3
23287     # =>
23288     #   c1/shift 4/subop/left *(ebp+8) 3/imm8
23289     #
23290     # . prologue
23291     55/push-ebp
23292     89/<- %ebp 4/r32/esp
23293     # setup
23294     (clear-stream _test-output-stream)
23295     (clear-stream $_test-output-buffered-file->buffer)
23296 $test-shift-mem-by-literal:initialize-type:
23297     # var type/ecx: (payload type-tree) = int
23298     68/push 0/imm32/right:null
23299     68/push 0/imm32/right:null
23300     68/push 0/imm32/left:unused
23301     68/push 1/imm32/value:int
23302     68/push 1/imm32/is-atom?:true
23303     68/push 0x11/imm32/alloc-id:fake:payload
23304     89/<- %ecx 4/r32/esp
23305 $test-shift-mem-by-literal:initialize-var1:
23306     # var var1/ecx: (payload var)
23307     68/push 0/imm32/register
23308     68/push 0/imm32/register
23309     68/push 8/imm32/stack-offset
23310     68/push 1/imm32/block-depth
23311     51/push-ecx
23312     68/push 0x11/imm32/alloc-id:fake
23313     68/push 0/imm32/name
23314     68/push 0/imm32/name
23315     68/push 0x11/imm32/alloc-id:fake:payload
23316     89/<- %ecx 4/r32/esp
23317 $test-shift-mem-by-literal:initialize-var1-name:
23318     # var1->name = "var1"
23319     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23320     (copy-array Heap "var1" %eax)
23321 $test-shift-mem-by-literal:initialize-literal-type:
23322     # var type/edx: (payload type-tree) = literal
23323     68/push 0/imm32/right:null
23324     68/push 0/imm32/right:null
23325     68/push 0/imm32/left:unused
23326     68/push 0/imm32/value:literal
23327     68/push 1/imm32/is-atom?:true
23328     68/push 0x11/imm32/alloc-id:fake:payload
23329     89/<- %edx 4/r32/esp
23330 $test-shift-mem-by-literal:initialize-literal:
23331     # var l/edx: (payload var)
23332     68/push 0/imm32/register
23333     68/push 0/imm32/register
23334     68/push 0/imm32/no-stack-offset
23335     68/push 1/imm32/block-depth
23336     52/push-edx
23337     68/push 0x11/imm32/alloc-id:fake
23338     68/push 0/imm32/name
23339     68/push 0/imm32/name
23340     68/push 0x11/imm32/alloc-id:fake:payload
23341     89/<- %edx 4/r32/esp
23342 $test-shift-mem-by-literal:initialize-literal-value:
23343     # l->name = "3"
23344     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23345     (copy-array Heap "3" %eax)
23346 $test-shift-mem-by-literal:initialize-inouts:
23347     # var inouts/esi: (payload stmt-var) = [l]
23348     68/push 0/imm32/is-deref:false
23349     68/push 0/imm32/next
23350     68/push 0/imm32/next
23351     52/push-edx/l
23352     68/push 0x11/imm32/alloc-id:fake
23353     68/push 0x11/imm32/alloc-id:fake:payload
23354     89/<- %esi 4/r32/esp
23355     # var inouts = (handle stmt-var) = [var1, var2]
23356     68/push 0/imm32/is-deref:false
23357     56/push-esi/next
23358     68/push 0x11/imm32/alloc-id:fake
23359     51/push-ecx/var1
23360     68/push 0x11/imm32/alloc-id:fake
23361     68/push 0x11/imm32/alloc-id:fake:payload
23362     89/<- %esi 4/r32/esp
23363 $test-shift-mem-by-literal:initialize-stmt:
23364     # var stmt/esi: (addr statement)
23365     68/push 0/imm32/next
23366     68/push 0/imm32/next
23367     68/push 0/imm32/outputs
23368     68/push 0/imm32/outputs
23369     56/push-esi/inouts
23370     68/push 0x11/imm32/alloc-id:fake
23371     68/push 0/imm32/operation
23372     68/push 0/imm32/operation
23373     68/push 1/imm32/tag:stmt1
23374     89/<- %esi 4/r32/esp
23375 $test-shift-mem-by-literal:initialize-stmt-operation:
23376     # stmt->operation = "shift-left"
23377     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23378     (copy-array Heap "shift-left" %eax)
23379     # convert
23380     c7 0/subop/copy *Curr-block-depth 0/imm32
23381     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23382     (flush _test-output-buffered-file)
23383 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23389     # check output
23390     (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
23391     # . epilogue
23392     89/<- %esp 5/r32/ebp
23393     5d/pop-to-ebp
23394     c3/return
23395 
23396 test-compare-reg-with-reg:
23397     #   compare var1/ecx, var2/eax
23398     # =>
23399     #   39/compare %ecx 0/r32/eax
23400     #
23401     # . prologue
23402     55/push-ebp
23403     89/<- %ebp 4/r32/esp
23404     # setup
23405     (clear-stream _test-output-stream)
23406     (clear-stream $_test-output-buffered-file->buffer)
23407 $test-compare-reg-with-reg:initialize-type:
23408     # var type/ecx: (payload type-tree) = int
23409     68/push 0/imm32/right:null
23410     68/push 0/imm32/right:null
23411     68/push 0/imm32/left:unused
23412     68/push 1/imm32/value:int
23413     68/push 1/imm32/is-atom?:true
23414     68/push 0x11/imm32/alloc-id:fake:payload
23415     89/<- %ecx 4/r32/esp
23416 $test-compare-reg-with-reg:initialize-var1:
23417     # var var1/ecx: (payload var)
23418     68/push 0/imm32/register
23419     68/push 0/imm32/register
23420     68/push 0/imm32/no-stack-offset
23421     68/push 1/imm32/block-depth
23422     51/push-ecx
23423     68/push 0x11/imm32/alloc-id:fake
23424     68/push 0/imm32/name
23425     68/push 0/imm32/name
23426     68/push 0x11/imm32/alloc-id:fake:payload
23427     89/<- %ecx 4/r32/esp
23428 $test-compare-reg-with-reg:initialize-var1-name:
23429     # var1->name = "var1"
23430     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23431     (copy-array Heap "var1" %eax)
23432 $test-compare-reg-with-reg:initialize-var1-register:
23433     # var1->register = "ecx"
23434     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23435     (copy-array Heap "ecx" %eax)
23436 $test-compare-reg-with-reg:initialize-var2:
23437     # var var2/edx: (payload var)
23438     68/push 0/imm32/register
23439     68/push 0/imm32/register
23440     68/push 0/imm32/no-stack-offset
23441     68/push 1/imm32/block-depth
23442     ff 6/subop/push *(ecx+0x10)
23443     68/push 0x11/imm32/alloc-id:fake
23444     68/push 0/imm32/name
23445     68/push 0/imm32/name
23446     68/push 0x11/imm32/alloc-id:fake:payload
23447     89/<- %edx 4/r32/esp
23448 $test-compare-reg-with-reg:initialize-var2-name:
23449     # var2->name = "var2"
23450     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23451     (copy-array Heap "var2" %eax)
23452 $test-compare-reg-with-reg:initialize-var2-register:
23453     # var2->register = "eax"
23454     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23455     (copy-array Heap "eax" %eax)
23456 $test-compare-reg-with-reg:initialize-inouts:
23457     # var inouts/esi: (payload stmt-var) = [var2]
23458     68/push 0/imm32/is-deref:false
23459     68/push 0/imm32/next
23460     68/push 0/imm32/next
23461     52/push-edx/var2
23462     68/push 0x11/imm32/alloc-id:fake
23463     68/push 0x11/imm32/alloc-id:fake:payload
23464     89/<- %esi 4/r32/esp
23465     # inouts = [var1, var2]
23466     68/push 0/imm32/is-deref:false
23467     56/push-esi/next
23468     68/push 0x11/imm32/alloc-id:fake
23469     51/push-ecx/var1
23470     68/push 0x11/imm32/alloc-id:fake
23471     68/push 0x11/imm32/alloc-id:fake:payload
23472     89/<- %esi 4/r32/esp
23473 $test-compare-reg-with-reg:initialize-stmt:
23474     # var stmt/esi: (addr statement)
23475     68/push 0/imm32/next
23476     68/push 0/imm32/next
23477     68/push 0/imm32/outputs
23478     68/push 0/imm32/outputs
23479     56/push-esi/inouts
23480     68/push 0x11/imm32/alloc-id:fake
23481     68/push 0/imm32/operation
23482     68/push 0/imm32/operation
23483     68/push 1/imm32/tag:stmt1
23484     89/<- %esi 4/r32/esp
23485 $test-compare-reg-with-reg:initialize-stmt-operation:
23486     # stmt->operation = "compare"
23487     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23488     (copy-array Heap "compare" %eax)
23489     # convert
23490     c7 0/subop/copy *Curr-block-depth 0/imm32
23491     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23492     (flush _test-output-buffered-file)
23493 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23499     # check output
23500     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
23501     # . epilogue
23502     89/<- %esp 5/r32/ebp
23503     5d/pop-to-ebp
23504     c3/return
23505 
23506 test-compare-mem-with-reg:
23507     #   compare var1, var2/eax
23508     # =>
23509     #   39/compare *(ebp+___) 0/r32/eax
23510     #
23511     # . prologue
23512     55/push-ebp
23513     89/<- %ebp 4/r32/esp
23514     # setup
23515     (clear-stream _test-output-stream)
23516     (clear-stream $_test-output-buffered-file->buffer)
23517 $test-compare-mem-with-reg:initialize-type:
23518     # var type/ecx: (payload type-tree) = int
23519     68/push 0/imm32/right:null
23520     68/push 0/imm32/right:null
23521     68/push 0/imm32/left:unused
23522     68/push 1/imm32/value:int
23523     68/push 1/imm32/is-atom?:true
23524     68/push 0x11/imm32/alloc-id:fake:payload
23525     89/<- %ecx 4/r32/esp
23526 $test-compare-mem-with-reg:initialize-var1:
23527     # var var1/ecx: (payload var)
23528     68/push 0/imm32/register
23529     68/push 0/imm32/register
23530     68/push 8/imm32/stack-offset
23531     68/push 1/imm32/block-depth
23532     51/push-ecx
23533     68/push 0x11/imm32/alloc-id:fake
23534     68/push 0/imm32/name
23535     68/push 0/imm32/name
23536     68/push 0x11/imm32/alloc-id:fake:payload
23537     89/<- %ecx 4/r32/esp
23538 $test-compare-mem-with-reg:initialize-var1-name:
23539     # var1->name = "var1"
23540     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23541     (copy-array Heap "var1" %eax)
23542 $test-compare-mem-with-reg:initialize-var2:
23543     # var var2/edx: (payload var)
23544     68/push 0/imm32/register
23545     68/push 0/imm32/register
23546     68/push 0/imm32/no-stack-offset
23547     68/push 1/imm32/block-depth
23548     ff 6/subop/push *(ecx+0x10)
23549     68/push 0x11/imm32/alloc-id:fake
23550     68/push 0/imm32/name
23551     68/push 0/imm32/name
23552     68/push 0x11/imm32/alloc-id:fake:payload
23553     89/<- %edx 4/r32/esp
23554 $test-compare-mem-with-reg:initialize-var2-name:
23555     # var2->name = "var2"
23556     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23557     (copy-array Heap "var2" %eax)
23558 $test-compare-mem-with-reg:initialize-var2-register:
23559     # var2->register = "eax"
23560     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
23561     (copy-array Heap "eax" %eax)
23562 $test-compare-mem-with-reg:initialize-inouts:
23563     # var inouts/esi: (payload stmt-var) = [var2]
23564     68/push 0/imm32/is-deref:false
23565     68/push 0/imm32/next
23566     68/push 0/imm32/next
23567     52/push-edx/var2
23568     68/push 0x11/imm32/alloc-id:fake
23569     68/push 0x11/imm32/alloc-id:fake:payload
23570     89/<- %esi 4/r32/esp
23571     # inouts = [var1, var2]
23572     68/push 0/imm32/is-deref:false
23573     56/push-esi/next
23574     68/push 0x11/imm32/alloc-id:fake
23575     51/push-ecx/var1
23576     68/push 0x11/imm32/alloc-id:fake
23577     68/push 0x11/imm32/alloc-id:fake:payload
23578     89/<- %esi 4/r32/esp
23579 $test-compare-mem-with-reg:initialize-stmt:
23580     # var stmt/esi: (addr statement)
23581     68/push 0/imm32/next
23582     68/push 0/imm32/next
23583     68/push 0/imm32/outputs
23584     68/push 0/imm32/outputs
23585     56/push-esi/inouts
23586     68/push 0x11/imm32/alloc-id:fake
23587     68/push 0/imm32/operation
23588     68/push 0/imm32/operation
23589     68/push 1/imm32/tag:stmt1
23590     89/<- %esi 4/r32/esp
23591 $test-compare-mem-with-reg:initialize-stmt-operation:
23592     # stmt->operation = "compare"
23593     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23594     (copy-array Heap "compare" %eax)
23595     # convert
23596     c7 0/subop/copy *Curr-block-depth 0/imm32
23597     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23598     (flush _test-output-buffered-file)
23599 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23605     # check output
23606     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
23607     # . epilogue
23608     89/<- %esp 5/r32/ebp
23609     5d/pop-to-ebp
23610     c3/return
23611 
23612 test-compare-reg-with-mem:
23613     #   compare var1/eax, var2
23614     # =>
23615     #   3b/compare<- *(ebp+___) 0/r32/eax
23616     #
23617     # . prologue
23618     55/push-ebp
23619     89/<- %ebp 4/r32/esp
23620     # setup
23621     (clear-stream _test-output-stream)
23622     (clear-stream $_test-output-buffered-file->buffer)
23623 $test-compare-reg-with-mem:initialize-type:
23624     # var type/ecx: (payload type-tree) = int
23625     68/push 0/imm32/right:null
23626     68/push 0/imm32/right:null
23627     68/push 0/imm32/left:unused
23628     68/push 1/imm32/value:int
23629     68/push 1/imm32/is-atom?:true
23630     68/push 0x11/imm32/alloc-id:fake:payload
23631     89/<- %ecx 4/r32/esp
23632 $test-compare-reg-with-mem:initialize-var1:
23633     # var var1/ecx: (payload var)
23634     68/push 0/imm32/register
23635     68/push 0/imm32/register
23636     68/push 0/imm32/no-stack-offset
23637     68/push 1/imm32/block-depth
23638     51/push-ecx
23639     68/push 0x11/imm32/alloc-id:fake
23640     68/push 0/imm32/name
23641     68/push 0/imm32/name
23642     68/push 0x11/imm32/alloc-id:fake:payload
23643     89/<- %ecx 4/r32/esp
23644 $test-compare-reg-with-mem:initialize-var1-name:
23645     # var1->name = "var1"
23646     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23647     (copy-array Heap "var1" %eax)
23648 $test-compare-reg-with-mem:initialize-var1-register:
23649     # var1->register = "eax"
23650     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23651     (copy-array Heap "eax" %eax)
23652 $test-compare-reg-with-mem:initialize-var2:
23653     # var var2/edx: (payload var)
23654     68/push 0/imm32/register
23655     68/push 0/imm32/register
23656     68/push 8/imm32/stack-offset
23657     68/push 1/imm32/block-depth
23658     ff 6/subop/push *(ecx+0x10)
23659     68/push 0x11/imm32/alloc-id:fake
23660     68/push 0/imm32/name
23661     68/push 0/imm32/name
23662     68/push 0x11/imm32/alloc-id:fake:payload
23663     89/<- %edx 4/r32/esp
23664 $test-compare-reg-with-mem:initialize-var2-name:
23665     # var2->name = "var2"
23666     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23667     (copy-array Heap "var2" %eax)
23668 $test-compare-reg-with-mem:initialize-inouts:
23669     # var inouts/esi: (payload stmt-var) = [var2]
23670     68/push 0/imm32/is-deref:false
23671     68/push 0/imm32/next
23672     68/push 0/imm32/next
23673     52/push-edx/var2
23674     68/push 0x11/imm32/alloc-id:fake
23675     68/push 0x11/imm32/alloc-id:fake:payload
23676     89/<- %esi 4/r32/esp
23677     # inouts = [var1, var2]
23678     68/push 0/imm32/is-deref:false
23679     56/push-esi/next
23680     68/push 0x11/imm32/alloc-id:fake
23681     51/push-ecx/var1
23682     68/push 0x11/imm32/alloc-id:fake
23683     68/push 0x11/imm32/alloc-id:fake:payload
23684     89/<- %esi 4/r32/esp
23685 $test-compare-reg-with-mem:initialize-stmt:
23686     # var stmt/esi: (addr statement)
23687     68/push 0/imm32/next
23688     68/push 0/imm32/next
23689     68/push 0/imm32/outputs
23690     68/push 0/imm32/outputs
23691     56/push-esi/inouts
23692     68/push 0x11/imm32/alloc-id:fake
23693     68/push 0/imm32/operation
23694     68/push 0/imm32/operation
23695     68/push 1/imm32/tag:stmt1
23696     89/<- %esi 4/r32/esp
23697 $test-compare-reg-with-mem:initialize-stmt-operation:
23698     # stmt->operation = "compare"
23699     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23700     (copy-array Heap "compare" %eax)
23701     # convert
23702     c7 0/subop/copy *Curr-block-depth 0/imm32
23703     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23704     (flush _test-output-buffered-file)
23705 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23711     # check output
23712     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
23713     # . epilogue
23714     89/<- %esp 5/r32/ebp
23715     5d/pop-to-ebp
23716     c3/return
23717 
23718 test-compare-mem-with-literal:
23719     #   compare var1, 0x34
23720     # =>
23721     #   81 7/subop/compare *(ebp+___) 0x34/imm32
23722     #
23723     # . prologue
23724     55/push-ebp
23725     89/<- %ebp 4/r32/esp
23726     # setup
23727     (clear-stream _test-output-stream)
23728     (clear-stream $_test-output-buffered-file->buffer)
23729 $test-compare-mem-with-literal:initialize-type:
23730     # var type/ecx: (payload type-tree) = int
23731     68/push 0/imm32/right:null
23732     68/push 0/imm32/right:null
23733     68/push 0/imm32/left:unused
23734     68/push 1/imm32/value:int
23735     68/push 1/imm32/is-atom?:true
23736     68/push 0x11/imm32/alloc-id:fake:payload
23737     89/<- %ecx 4/r32/esp
23738 $test-compare-mem-with-literal:initialize-var1:
23739     # var var1/ecx: (payload var)
23740     68/push 0/imm32/register
23741     68/push 0/imm32/register
23742     68/push 8/imm32/stack-offset
23743     68/push 1/imm32/block-depth
23744     51/push-ecx
23745     68/push 0x11/imm32/alloc-id:fake
23746     68/push 0/imm32/name
23747     68/push 0/imm32/name
23748     68/push 0x11/imm32/alloc-id:fake:payload
23749     89/<- %ecx 4/r32/esp
23750 $test-compare-mem-with-literal:initialize-var1-name:
23751     # var1->name = "var1"
23752     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23753     (copy-array Heap "var1" %eax)
23754 $test-compare-mem-with-literal:initialize-literal-type:
23755     # var type/edx: (payload type-tree) = literal
23756     68/push 0/imm32/right:null
23757     68/push 0/imm32/right:null
23758     68/push 0/imm32/left:unused
23759     68/push 0/imm32/value:literal
23760     68/push 1/imm32/is-atom?:true
23761     68/push 0x11/imm32/alloc-id:fake:payload
23762     89/<- %edx 4/r32/esp
23763 $test-compare-mem-with-literal:initialize-literal:
23764     # var l/edx: (payload var)
23765     68/push 0/imm32/register
23766     68/push 0/imm32/register
23767     68/push 0/imm32/no-stack-offset
23768     68/push 1/imm32/block-depth
23769     52/push-edx
23770     68/push 0x11/imm32/alloc-id:fake
23771     68/push 0/imm32/name
23772     68/push 0/imm32/name
23773     68/push 0x11/imm32/alloc-id:fake:payload
23774     89/<- %edx 4/r32/esp
23775 $test-compare-mem-with-literal:initialize-literal-value:
23776     # l->name = "0x34"
23777     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23778     (copy-array Heap "0x34" %eax)
23779 $test-compare-mem-with-literal:initialize-inouts:
23780     # var inouts/esi: (payload stmt-var) = [l]
23781     68/push 0/imm32/is-deref:false
23782     68/push 0/imm32/next
23783     68/push 0/imm32/next
23784     52/push-edx/l
23785     68/push 0x11/imm32/alloc-id:fake
23786     68/push 0x11/imm32/alloc-id:fake:payload
23787     89/<- %esi 4/r32/esp
23788     # var inouts = (handle stmt-var) = [var1, var2]
23789     68/push 0/imm32/is-deref:false
23790     56/push-esi/next
23791     68/push 0x11/imm32/alloc-id:fake
23792     51/push-ecx/var1
23793     68/push 0x11/imm32/alloc-id:fake
23794     68/push 0x11/imm32/alloc-id:fake:payload
23795     89/<- %esi 4/r32/esp
23796 $test-compare-mem-with-literal:initialize-stmt:
23797     # var stmt/esi: (addr statement)
23798     68/push 0/imm32/next
23799     68/push 0/imm32/next
23800     68/push 0/imm32/outputs
23801     68/push 0/imm32/outputs
23802     56/push-esi/inouts
23803     68/push 0x11/imm32/alloc-id:fake
23804     68/push 0/imm32/operation
23805     68/push 0/imm32/operation
23806     68/push 1/imm32/tag:stmt1
23807     89/<- %esi 4/r32/esp
23808 $test-compare-mem-with-literal:initialize-stmt-operation:
23809     # stmt->operation = "compare"
23810     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23811     (copy-array Heap "compare" %eax)
23812     # convert
23813     c7 0/subop/copy *Curr-block-depth 0/imm32
23814     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23815     (flush _test-output-buffered-file)
23816 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23822     # check output
23823     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
23824     # . epilogue
23825     89/<- %esp 5/r32/ebp
23826     5d/pop-to-ebp
23827     c3/return
23828 
23829 test-compare-eax-with-literal:
23830     #   compare var1/eax 0x34
23831     # =>
23832     #   3d/compare-eax-with 0x34/imm32
23833     #
23834     # . prologue
23835     55/push-ebp
23836     89/<- %ebp 4/r32/esp
23837     # setup
23838     (clear-stream _test-output-stream)
23839     (clear-stream $_test-output-buffered-file->buffer)
23840 $test-compare-eax-with-literal:initialize-type:
23841     # var type/ecx: (payload type-tree) = int
23842     68/push 0/imm32/right:null
23843     68/push 0/imm32/right:null
23844     68/push 0/imm32/left:unused
23845     68/push 1/imm32/value:int
23846     68/push 1/imm32/is-atom?:true
23847     68/push 0x11/imm32/alloc-id:fake:payload
23848     89/<- %ecx 4/r32/esp
23849 $test-compare-eax-with-literal:initialize-var1:
23850     # var var1/ecx: (payload var)
23851     68/push 0/imm32/register
23852     68/push 0/imm32/register
23853     68/push 0/imm32/no-stack-offset
23854     68/push 1/imm32/block-depth
23855     51/push-ecx
23856     68/push 0x11/imm32/alloc-id:fake
23857     68/push 0/imm32/name
23858     68/push 0/imm32/name
23859     68/push 0x11/imm32/alloc-id:fake:payload
23860     89/<- %ecx 4/r32/esp
23861 $test-compare-eax-with-literal:initialize-var1-name:
23862     # var1->name = "var1"
23863     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23864     (copy-array Heap "var1" %eax)
23865 $test-compare-eax-with-literal:initialize-var1-register:
23866     # v->register = "eax"
23867     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23868     (copy-array Heap "eax" %eax)
23869 $test-compare-eax-with-literal:initialize-literal-type:
23870     # var type/edx: (payload type-tree) = literal
23871     68/push 0/imm32/right:null
23872     68/push 0/imm32/right:null
23873     68/push 0/imm32/left:unused
23874     68/push 0/imm32/value:literal
23875     68/push 1/imm32/is-atom?:true
23876     68/push 0x11/imm32/alloc-id:fake:payload
23877     89/<- %edx 4/r32/esp
23878 $test-compare-eax-with-literal:initialize-literal:
23879     # var l/edx: (payload var)
23880     68/push 0/imm32/register
23881     68/push 0/imm32/register
23882     68/push 0/imm32/no-stack-offset
23883     68/push 1/imm32/block-depth
23884     52/push-edx
23885     68/push 0x11/imm32/alloc-id:fake
23886     68/push 0/imm32/name
23887     68/push 0/imm32/name
23888     68/push 0x11/imm32/alloc-id:fake:payload
23889     89/<- %edx 4/r32/esp
23890 $test-compare-eax-with-literal:initialize-literal-value:
23891     # l->name = "0x34"
23892     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
23893     (copy-array Heap "0x34" %eax)
23894 $test-compare-eax-with-literal:initialize-inouts:
23895     # var inouts/esi: (payload stmt-var) = [l]
23896     68/push 0/imm32/is-deref:false
23897     68/push 0/imm32/next
23898     68/push 0/imm32/next
23899     52/push-edx/l
23900     68/push 0x11/imm32/alloc-id:fake
23901     68/push 0x11/imm32/alloc-id:fake:payload
23902     89/<- %esi 4/r32/esp
23903     # var inouts = (handle stmt-var) = [var1, var2]
23904     68/push 0/imm32/is-deref:false
23905     56/push-esi/next
23906     68/push 0x11/imm32/alloc-id:fake
23907     51/push-ecx/var1
23908     68/push 0x11/imm32/alloc-id:fake
23909     68/push 0x11/imm32/alloc-id:fake:payload
23910     89/<- %esi 4/r32/esp
23911 $test-compare-eax-with-literal:initialize-stmt:
23912     # var stmt/esi: (addr statement)
23913     68/push 0/imm32/next
23914     68/push 0/imm32/next
23915     68/push 0/imm32/outputs
23916     68/push 0/imm32/outputs
23917     56/push-esi/inouts
23918     68/push 0x11/imm32/alloc-id:fake
23919     68/push 0/imm32/operation
23920     68/push 0/imm32/operation
23921     68/push 1/imm32/tag:stmt1
23922     89/<- %esi 4/r32/esp
23923 $test-compare-eax-with-literal:initialize-stmt-operation:
23924     # stmt->operation = "compare"
23925     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
23926     (copy-array Heap "compare" %eax)
23927     # convert
23928     c7 0/subop/copy *Curr-block-depth 0/imm32
23929     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
23930     (flush _test-output-buffered-file)
23931 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
23937     # check output
23938     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
23939     # . epilogue
23940     89/<- %esp 5/r32/ebp
23941     5d/pop-to-ebp
23942     c3/return
23943 
23944 test-compare-reg-with-literal:
23945     #   compare var1/ecx 0x34
23946     # =>
23947     #   81 7/subop/compare %ecx 0x34/imm32
23948     #
23949     # . prologue
23950     55/push-ebp
23951     89/<- %ebp 4/r32/esp
23952     # setup
23953     (clear-stream _test-output-stream)
23954     (clear-stream $_test-output-buffered-file->buffer)
23955 $test-compare-reg-with-literal:initialize-type:
23956     # var type/ecx: (payload type-tree) = int
23957     68/push 0/imm32/right:null
23958     68/push 0/imm32/right:null
23959     68/push 0/imm32/left:unused
23960     68/push 1/imm32/value:int
23961     68/push 1/imm32/is-atom?:true
23962     68/push 0x11/imm32/alloc-id:fake:payload
23963     89/<- %ecx 4/r32/esp
23964 $test-compare-reg-with-literal:initialize-var1:
23965     # var var1/ecx: (payload var)
23966     68/push 0/imm32/register
23967     68/push 0/imm32/register
23968     68/push 0/imm32/no-stack-offset
23969     68/push 1/imm32/block-depth
23970     51/push-ecx
23971     68/push 0x11/imm32/alloc-id:fake
23972     68/push 0/imm32/name
23973     68/push 0/imm32/name
23974     68/push 0x11/imm32/alloc-id:fake:payload
23975     89/<- %ecx 4/r32/esp
23976 $test-compare-reg-with-literal:initialize-var1-name:
23977     # var1->name = "var1"
23978     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
23979     (copy-array Heap "var1" %eax)
23980 $test-compare-reg-with-literal:initialize-var1-register:
23981     # v->register = "ecx"
23982     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
23983     (copy-array Heap "ecx" %eax)
23984 $test-compare-reg-with-literal:initialize-literal-type:
23985     # var type/edx: (payload type-tree) = literal
23986     68/push 0/imm32/right:null
23987     68/push 0/imm32/right:null
23988     68/push 0/imm32/left:unused
23989     68/push 0/imm32/value:literal
23990     68/push 1/imm32/is-atom?:true
23991     68/push 0x11/imm32/alloc-id:fake:payload
23992     89/<- %edx 4/r32/esp
23993 $test-compare-reg-with-literal:initialize-literal:
23994     # var l/edx: (payload var)
23995     68/push 0/imm32/register
23996     68/push 0/imm32/register
23997     68/push 0/imm32/no-stack-offset
23998     68/push 1/imm32/block-depth
23999     52/push-edx
24000     68/push 0x11/imm32/alloc-id:fake
24001     68/push 0/imm32/name
24002     68/push 0/imm32/name
24003     68/push 0x11/imm32/alloc-id:fake:payload
24004     89/<- %edx 4/r32/esp
24005 $test-compare-reg-with-literal:initialize-literal-value:
24006     # l->name = "0x34"
24007     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
24008     (copy-array Heap "0x34" %eax)
24009 $test-compare-reg-with-literal:initialize-inouts:
24010     # var inouts/esi: (payload stmt-var) = [l]
24011     68/push 0/imm32/is-deref:false
24012     68/push 0/imm32/next
24013     68/push 0/imm32/next
24014     52/push-edx/l
24015     68/push 0x11/imm32/alloc-id:fake
24016     68/push 0x11/imm32/alloc-id:fake:payload
24017     89/<- %esi 4/r32/esp
24018     # var inouts = (handle stmt-var) = [var1, var2]
24019     68/push 0/imm32/is-deref:false
24020     56/push-esi/next
24021     68/push 0x11/imm32/alloc-id:fake
24022     51/push-ecx/var1
24023     68/push 0x11/imm32/alloc-id:fake
24024     68/push 0x11/imm32/alloc-id:fake:payload
24025     89/<- %esi 4/r32/esp
24026 $test-compare-reg-with-literal:initialize-stmt:
24027     # var stmt/esi: (addr statement)
24028     68/push 0/imm32/next
24029     68/push 0/imm32/next
24030     68/push 0/imm32/outputs
24031     68/push 0/imm32/outputs
24032     56/push-esi/inouts
24033     68/push 0x11/imm32/alloc-id:fake
24034     68/push 0/imm32/operation
24035     68/push 0/imm32/operation
24036     68/push 1/imm32/tag:stmt1
24037     89/<- %esi 4/r32/esp
24038 $test-compare-reg-with-literal:initialize-stmt-operation:
24039     # stmt->operation = "compare"
24040     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24041     (copy-array Heap "compare" %eax)
24042     # convert
24043     c7 0/subop/copy *Curr-block-depth 0/imm32
24044     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
24045     (flush _test-output-buffered-file)
24046 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24052     # check output
24053     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
24054     # . epilogue
24055     89/<- %esp 5/r32/ebp
24056     5d/pop-to-ebp
24057     c3/return
24058 
24059 test-emit-subx-stmt-function-call:
24060     # Call a function on a variable on the stack.
24061     #   f foo
24062     # =>
24063     #   (f *(ebp-8))
24064     # (Changing the function name supports overloading in general, but here it
24065     # just serves to help disambiguate things.)
24066     #
24067     # There's a variable on the var stack as follows:
24068     #   name: 'foo'
24069     #   type: int
24070     #   stack-offset: -8
24071     #
24072     # There's nothing in primitives.
24073     #
24074     # We don't perform any checking here on the type of 'f'.
24075     #
24076     # . prologue
24077     55/push-ebp
24078     89/<- %ebp 4/r32/esp
24079     # setup
24080     (clear-stream _test-output-stream)
24081     (clear-stream $_test-output-buffered-file->buffer)
24082 $test-emit-subx-function-call:initialize-type:
24083     # var type/ecx: (payload type-tree) = int
24084     68/push 0/imm32/right:null
24085     68/push 0/imm32/right:null
24086     68/push 0/imm32/left:unused
24087     68/push 1/imm32/value:int
24088     68/push 1/imm32/is-atom?:true
24089     68/push 0x11/imm32/alloc-id:fake:payload
24090     89/<- %ecx 4/r32/esp
24091 $test-emit-subx-function-call:initialize-var:
24092     # var var-foo/ecx: (payload var) = var(type)
24093     68/push 0/imm32/no-register
24094     68/push 0/imm32/no-register
24095     68/push -8/imm32/stack-offset
24096     68/push 1/imm32/block-depth
24097     51/push-ecx/type
24098     68/push 0x11/imm32/alloc-id:fake
24099     68/push 0/imm32/name
24100     68/push 0/imm32/name
24101     68/push 0x11/imm32/alloc-id:fake:payload
24102     89/<- %ecx 4/r32/esp
24103 $test-emit-subx-function-call:initialize-var-name:
24104     # var-foo->name = "foo"
24105     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24106     (copy-array Heap "foo" %eax)
24107 $test-emit-subx-function-call:initialize-stmt-var:
24108     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
24109     68/push 0/imm32/is-deref:false
24110     68/push 0/imm32/next
24111     68/push 0/imm32/next
24112     51/push-ecx/var-foo
24113     68/push 0x11/imm32/alloc-id:fake
24114     68/push 0x11/imm32/alloc-id:fake:payload
24115     89/<- %ebx 4/r32/esp
24116 $test-emit-subx-function-call:initialize-stmt:
24117     # var stmt/esi: (addr statement)
24118     68/push 0/imm32/no-outputs
24119     68/push 0/imm32/no-outputs
24120     53/push-ebx/inouts
24121     68/push 0x11/imm32/alloc-id:fake
24122     68/push 0/imm32/operation
24123     68/push 0/imm32/operation
24124     68/push 1/imm32/tag
24125     89/<- %esi 4/r32/esp
24126 $test-emit-subx-function-call:initialize-stmt-operation:
24127     # stmt->operation = "f"
24128     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24129     (copy-array Heap "f" %eax)
24130     # convert
24131     c7 0/subop/copy *Curr-block-depth 0/imm32
24132     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
24133     (flush _test-output-buffered-file)
24134 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24140     # check output
24141     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
24142     # . epilogue
24143     89/<- %esp 5/r32/ebp
24144     5d/pop-to-ebp
24145     c3/return
24146 
24147 test-emit-subx-stmt-function-call-with-literal-arg:
24148     # Call a function on a literal.
24149     #   f 0x34
24150     # =>
24151     #   (f2 0x34)
24152     #
24153     # . prologue
24154     55/push-ebp
24155     89/<- %ebp 4/r32/esp
24156     # setup
24157     (clear-stream _test-output-stream)
24158     (clear-stream $_test-output-buffered-file->buffer)
24159 $test-emit-subx-function-call-with-literal-arg:initialize-type:
24160     # var type/ecx: (payload type-tree) = int
24161     68/push 0/imm32/right:null
24162     68/push 0/imm32/right:null
24163     68/push 0/imm32/left:unused
24164     68/push 0/imm32/value:literal
24165     68/push 1/imm32/is-atom?:true
24166     68/push 0x11/imm32/alloc-id:fake:payload
24167     89/<- %ecx 4/r32/esp
24168 $test-emit-subx-function-call-with-literal-arg:initialize-var:
24169     # var var-foo/ecx: (payload var) = var(lit)
24170     68/push 0/imm32/no-register
24171     68/push 0/imm32/no-register
24172     68/push 0/imm32/no-stack-offset
24173     68/push 1/imm32/block-depth
24174     51/push-ecx/type
24175     68/push 0x11/imm32/alloc-id:fake
24176     68/push 0/imm32/name
24177     68/push 0/imm32/name
24178     68/push 0x11/imm32/alloc-id:fake:payload
24179     89/<- %ecx 4/r32/esp
24180 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
24181     # var-foo->name = "0x34"
24182     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
24183     (copy-array Heap "0x34" %eax)
24184 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
24185     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
24186     68/push 0/imm32/is-deref:false
24187     68/push 0/imm32/next
24188     68/push 0/imm32/next
24189     51/push-ecx/var-foo
24190     68/push 0x11/imm32/alloc-id:fake
24191     68/push 0x11/imm32/alloc-id:fake:payload
24192     89/<- %ebx 4/r32/esp
24193 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
24194     # var stmt/esi: (addr statement)
24195     68/push 0/imm32/no-outputs
24196     68/push 0/imm32/no-outputs
24197     53/push-ebx/inouts
24198     68/push 0x11/imm32/alloc-id:fake
24199     68/push 0/imm32/operation
24200     68/push 0/imm32/operation
24201     68/push 1/imm32/tag
24202     89/<- %esi 4/r32/esp
24203 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
24204     # stmt->operation = "f"
24205     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
24206     (copy-array Heap "f" %eax)
24207     # convert
24208     c7 0/subop/copy *Curr-block-depth 0/imm32
24209     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
24210     (flush _test-output-buffered-file)
24211 +--  6 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------------------------------------------------------------
24217     # check output
24218     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
24219     # . epilogue
24220     89/<- %esp 5/r32/ebp
24221     5d/pop-to-ebp
24222     c3/return
24223 
24224 emit-indent:  # out: (addr buffered-file), n: int
24225     # . prologue
24226     55/push-ebp
24227     89/<- %ebp 4/r32/esp
24228     # . save registers
24229     50/push-eax
24230     # var i/eax: int = n
24231     8b/-> *(ebp+0xc) 0/r32/eax
24232     {
24233       # if (i <= 0) break
24234       3d/compare-eax-with 0/imm32
24235       7e/jump-if-<= break/disp8
24236       (write-buffered *(ebp+8) "  ")
24237       48/decrement-eax
24238       eb/jump loop/disp8
24239     }
24240 $emit-indent:end:
24241     # . restore registers
24242     58/pop-to-eax
24243     # . epilogue
24244     89/<- %esp 5/r32/ebp
24245     5d/pop-to-ebp
24246     c3/return
24247 
24248 emit-subx-prologue:  # out: (addr buffered-file)
24249     # . prologue
24250     55/push-ebp
24251     89/<- %ebp 4/r32/esp
24252     #
24253     (write-buffered *(ebp+8) "  # . prologue\n")
24254     (write-buffered *(ebp+8) "  55/push-ebp\n")
24255     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
24256 $emit-subx-prologue:end:
24257     # . epilogue
24258     89/<- %esp 5/r32/ebp
24259     5d/pop-to-ebp
24260     c3/return
24261 
24262 emit-subx-epilogue:  # out: (addr buffered-file)
24263     # . prologue
24264     55/push-ebp
24265     89/<- %ebp 4/r32/esp
24266     #
24267     (write-buffered *(ebp+8) "  # . epilogue\n")
24268     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
24269     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
24270     (write-buffered *(ebp+8) "  c3/return\n")
24271 $emit-subx-epilogue:end:
24272     # . epilogue
24273     89/<- %esp 5/r32/ebp
24274     5d/pop-to-ebp
24275     c3/return