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 tree type-id)
   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 tree type-id)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle tree type-id)
  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 tree type-id)
  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-disp32: enum arg-location
  212 #     output-is-write-only: boolean
  213 #   arg-location: enum
  214 #     0 means none
  215 #     1 means first inout
  216 #     2 means second inout
  217 #     3 means first output
  218 
  219 # == Translating a block
  220 # Emit block name if necessary
  221 # Emit '{'
  222 # When you encounter a statement, emit it as above
  223 # When you encounter a variable declaration
  224 #   emit any code needed for it (bzeros)
  225 #   push it on the var stack
  226 #   update register dict if necessary
  227 # When you encounter '}'
  228 #   While popping variables off the var stack until block id changes
  229 #     Emit code needed to clean up the stack
  230 #       either increment esp
  231 #       or pop into appropriate register
  232 
  233 # The rest is straightforward.
  234 
  235 == data
  236 
  237 Program:
  238 _Program-functions:  # (handle function)
  239   0/imm32
  240 _Program-functions->payload:
  241   0/imm32
  242 _Program-types:  # (handle typeinfo)
  243   0/imm32
  244 _Program-types->payload:
  245   0/imm32
  246 
  247 # Some constants for simulating the data structures described above.
  248 # Many constants here come with a type in a comment.
  249 #
  250 # Sometimes the type is of the value at that offset for the given type. For
  251 # example, if you start at a function record and move forward Function-inouts
  252 # bytes, you'll find a (handle list var).
  253 #
  254 # At other times, the type is of the constant itself. For example, the type of
  255 # the constant Function-size is (addr int). To get the size of a function,
  256 # look in *Function-size.
  257 
  258 Function-name:  # (handle array byte)
  259   0/imm32
  260 Function-inouts:  # (handle list var)
  261   8/imm32
  262 Function-outputs:  # (handle list var)
  263   0x10/imm32
  264 Function-body:  # (handle block)
  265   0x18/imm32
  266 Function-next:  # (handle function)
  267   0x20/imm32
  268 Function-size:  # (addr int)
  269   0x28/imm32/40
  270 
  271 Primitive-name:  # (handle array byte)
  272   0/imm32
  273 Primitive-inouts:  # (handle list var)
  274   8/imm32
  275 Primitive-outputs:  # (handle list var)
  276   0x10/imm32
  277 Primitive-subx-name:  # (handle array byte)
  278   0x18/imm32
  279 Primitive-subx-rm32:  # enum arg-location
  280   0x20/imm32
  281 Primitive-subx-r32:  # enum arg-location
  282   0x24/imm32
  283 Primitive-subx-imm32:  # enum arg-location
  284   0x28/imm32
  285 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  286   0x2c/imm32
  287 Primitive-output-is-write-only:  # boolean
  288   0x30/imm32
  289 Primitive-next:  # (handle function)
  290   0x34/imm32
  291 Primitive-size:  # (addr int)
  292   0x3c/imm32/60
  293 
  294 Stmt-tag:  # int
  295   0/imm32
  296 
  297 Block-stmts:  # (handle list stmt)
  298   4/imm32
  299 Block-var:  # (handle var)
  300   0xc/imm32
  301 
  302 Stmt1-operation:  # (handle array byte)
  303   4/imm32
  304 Stmt1-inouts:  # (handle stmt-var)
  305   0xc/imm32
  306 Stmt1-outputs:  # (handle stmt-var)
  307   0x14/imm32
  308 
  309 Vardef-var:  # (handle var)
  310   4/imm32
  311 
  312 Regvardef-operation:  # (handle array byte)
  313   4/imm32
  314 Regvardef-inouts:  # (handle stmt-var)
  315   0xc/imm32
  316 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  317   0x14/imm32
  318 
  319 Stmt-size:  # (addr int)
  320   0x1c/imm32
  321 
  322 Var-name:  # (handle array byte)
  323   0/imm32
  324 Var-type:  # (handle tree type-id)
  325   8/imm32
  326 Var-block-depth:  # int -- not available until code-generation time
  327   0x10/imm32
  328 Var-offset:  # int -- not available until code-generation time
  329   0x14/imm32
  330 Var-register:  # (handle array byte) -- name of a register
  331   0x18/imm32
  332 Var-size:  # (addr int)
  333   0x20/imm32
  334 
  335 List-value:  # (handle _)
  336   0/imm32
  337 List-next:  # (handle list _)
  338   8/imm32
  339 List-size:  # (addr int)
  340   0x10/imm32
  341 
  342 # A stmt-var is like a list of vars with call-site specific metadata
  343 Stmt-var-value:  # (handle var)
  344   0/imm32
  345 Stmt-var-next:  # (handle stmt-var)
  346   8/imm32
  347 Stmt-var-is-deref:  # boolean
  348   0x10/imm32
  349 Stmt-var-size:  # (addr int)
  350   0x14/imm32
  351 
  352 # A live-var is a var augmented with information needed for tracking live
  353 # variables.
  354 Live-var-value:  # (handle var)
  355   0/imm32
  356 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  357   8/imm32
  358 Live-var-size:  # (addr int)
  359   0xc/imm32
  360 
  361 # Types are expressed as trees (s-expressions) of type-ids (ints).
  362 
  363 Tree-is-atom:  # boolean
  364   0/imm32
  365 # if left-is-atom?
  366 Tree-value:  # type-id
  367   4/imm32
  368 # unless left-is-atom?
  369 Tree-left:  # (addr tree type-id)
  370   4/imm32
  371 Tree-right:  # (addr tree type-id)
  372   0xc/imm32
  373 #
  374 Tree-size:  # (addr int)
  375   0x14/imm32
  376 
  377 # Types
  378 
  379 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  380 Type-id:  # (stream (addr array byte))
  381   0x20/imm32/write
  382   0/imm32/read
  383   0x100/imm32/size
  384   # data
  385   "literal"/imm32  # 0: value is just the name
  386   "int"/imm32  # 1
  387   "addr"/imm32  # 2
  388   "array"/imm32  # 3
  389   "handle"/imm32  # 4
  390   "boolean"/imm32  # 5
  391   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  392   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  393   # 0x20
  394   "byte"/imm32  # 8
  395           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  396   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  397   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  398   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  399   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  400   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  401   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  402 
  403 # == Type definitions
  404 # Program->types contains some typeinfo for each type definition.
  405 # Types contain vars with types, but can't specify registers.
  406 Typeinfo-id:  # type-id
  407   0/imm32
  408 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  409   4/imm32
  410 # Total size must be >= 0
  411 # During parsing it may take on two additional values:
  412 #   -2: not yet initialized
  413 #   -1: in process of being computed
  414 # See populate-mu-type-sizes for details.
  415 Typeinfo-total-size-in-bytes:  # int
  416   0xc/imm32
  417 Typeinfo-next:  # (handle typeinfo)
  418   0x10/imm32
  419 Typeinfo-size:  # (addr int)
  420   0x18/imm32
  421 
  422 # Each entry in the typeinfo->fields table has a pointer to a string and a
  423 # pointer to a typeinfo-entry.
  424 Typeinfo-fields-row-size:  # (addr int)
  425   0x10/imm32
  426 
  427 # typeinfo-entry objects have information about a field in a single record type
  428 #
  429 # each field of a type is represented using two var's:
  430 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  431 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  432 # computing the output happens after parsing; in the meantime we preserve the
  433 # order of fields in the 'index' field.
  434 Typeinfo-entry-input-var:  # (handle var)
  435   0/imm32
  436 Typeinfo-entry-index:  # int
  437   8/imm32
  438 Typeinfo-entry-output-var:  # (handle var)
  439   0xc/imm32
  440 Typeinfo-entry-size:  # (addr int)
  441   0x14/imm32
  442 
  443 == code
  444 
  445 Entry:
  446     # . prologue
  447     89/<- %ebp 4/r32/esp
  448     (new-segment *Heap-size Heap)
  449     # if (argv[1] == "test') run-tests()
  450     {
  451       # if (argc <= 1) break
  452       81 7/subop/compare *ebp 1/imm32
  453       7e/jump-if-<= break/disp8
  454       # if (argv[1] != "test") break
  455       (kernel-string-equal? *(ebp+8) "test")  # => eax
  456       3d/compare-eax-and 0/imm32/false
  457       74/jump-if-= break/disp8
  458       #
  459       (run-tests)
  460       # syscall(exit, *Num-test-failures)
  461       8b/-> *Num-test-failures 3/r32/ebx
  462       eb/jump $mu-main:end/disp8
  463     }
  464     # otherwise convert Stdin
  465     (convert-mu Stdin Stdout Stderr 0)
  466     (flush Stdout)
  467     # syscall(exit, 0)
  468     bb/copy-to-ebx 0/imm32
  469 $mu-main:end:
  470     e8/call syscall_exit/disp32
  471 
  472 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  473     # . prologue
  474     55/push-ebp
  475     89/<- %ebp 4/r32/esp
  476     # initialize global data structures
  477     c7 0/subop/copy *Next-block-index 1/imm32
  478     c7 0/subop/copy *Type-id 0x24/imm32  # stream-write
  479     c7 0/subop/copy *_Program-functions 0/imm32
  480     c7 0/subop/copy *_Program-functions->payload 0/imm32
  481     c7 0/subop/copy *_Program-types 0/imm32
  482     c7 0/subop/copy *_Program-types->payload 0/imm32
  483     #
  484     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  485     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  486 #?     (dump-typeinfos "=== typeinfos\n")
  487     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  488     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  489 $convert-mu:end:
  490     # . epilogue
  491     89/<- %esp 5/r32/ebp
  492     5d/pop-to-ebp
  493     c3/return
  494 
  495 test-convert-empty-input:
  496     # empty input => empty output
  497     # . prologue
  498     55/push-ebp
  499     89/<- %ebp 4/r32/esp
  500     # setup
  501     (clear-stream _test-input-stream)
  502     (clear-stream $_test-input-buffered-file->buffer)
  503     (clear-stream _test-output-stream)
  504     (clear-stream $_test-output-buffered-file->buffer)
  505     #
  506     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  507     (flush _test-output-buffered-file)
  508     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  509     # . epilogue
  510     89/<- %esp 5/r32/ebp
  511     5d/pop-to-ebp
  512     c3/return
  513 
  514 test-convert-function-skeleton:
  515     # . prologue
  516     55/push-ebp
  517     89/<- %ebp 4/r32/esp
  518     # setup
  519     (clear-stream _test-input-stream)
  520     (clear-stream $_test-input-buffered-file->buffer)
  521     (clear-stream _test-output-stream)
  522     (clear-stream $_test-output-buffered-file->buffer)
  523     #
  524     (write _test-input-stream "fn foo {\n")
  525     (write _test-input-stream "}\n")
  526     # convert
  527     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  528     (flush _test-output-buffered-file)
  529 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  535     # check output
  536     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  537     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  538     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  539     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  540     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  541     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  542     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  543     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  544     # . epilogue
  545     89/<- %esp 5/r32/ebp
  546     5d/pop-to-ebp
  547     c3/return
  548 
  549 test-convert-multiple-function-skeletons:
  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     (write _test-input-stream "fn bar {\n")
  562     (write _test-input-stream "}\n")
  563     # convert
  564     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  565     (flush _test-output-buffered-file)
  566 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  572     # check first function
  573     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  574     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  575     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  576     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  577     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  578     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  579     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  580     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  581     # check second function
  582     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  583     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  584     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  585     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  586     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  587     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  588     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  589     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  590     # . epilogue
  591     89/<- %esp 5/r32/ebp
  592     5d/pop-to-ebp
  593     c3/return
  594 
  595 test-convert-function-with-arg:
  596     # . prologue
  597     55/push-ebp
  598     89/<- %ebp 4/r32/esp
  599     # setup
  600     (clear-stream _test-input-stream)
  601     (clear-stream $_test-input-buffered-file->buffer)
  602     (clear-stream _test-output-stream)
  603     (clear-stream $_test-output-buffered-file->buffer)
  604     #
  605     (write _test-input-stream "fn foo n: int {\n")
  606     (write _test-input-stream "}\n")
  607     # convert
  608     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  609     (flush _test-output-buffered-file)
  610 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  616     # check output
  617     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  618     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  619     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  620     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  621     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  622     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  623     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  624     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  625     # . epilogue
  626     89/<- %esp 5/r32/ebp
  627     5d/pop-to-ebp
  628     c3/return
  629 
  630 test-convert-function-with-arg-and-body:
  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 "  increment n\n")
  642     (write _test-input-stream "}\n")
  643     # convert
  644     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  645     (flush _test-output-buffered-file)
  646 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  652     # check output
  653     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  654     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  655     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  656     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  657     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  658     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  659     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  660     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  661     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  662     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  663     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  664     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  665     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  666     # . epilogue
  667     89/<- %esp 5/r32/ebp
  668     5d/pop-to-ebp
  669     c3/return
  670 
  671 test-convert-function-distinguishes-args:
  672     # . prologue
  673     55/push-ebp
  674     89/<- %ebp 4/r32/esp
  675     # setup
  676     (clear-stream _test-input-stream)
  677     (clear-stream $_test-input-buffered-file->buffer)
  678     (clear-stream _test-output-stream)
  679     (clear-stream $_test-output-buffered-file->buffer)
  680     #
  681     (write _test-input-stream "fn foo a: int, b: int {\n")
  682     (write _test-input-stream "  increment b\n")
  683     (write _test-input-stream "}\n")
  684     # convert
  685     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  686     (flush _test-output-buffered-file)
  687 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  693     # check output
  694     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  695     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  696     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  697     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  698     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  700     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  701     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  702     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  703     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  704     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  705     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  706     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  707     # . epilogue
  708     89/<- %esp 5/r32/ebp
  709     5d/pop-to-ebp
  710     c3/return
  711 
  712 test-convert-function-returns-result:
  713     # . prologue
  714     55/push-ebp
  715     89/<- %ebp 4/r32/esp
  716     # setup
  717     (clear-stream _test-input-stream)
  718     (clear-stream $_test-input-buffered-file->buffer)
  719     (clear-stream _test-output-stream)
  720     (clear-stream $_test-output-buffered-file->buffer)
  721     #
  722     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  723     (write _test-input-stream "  result <- copy a\n")
  724     (write _test-input-stream "  result <- increment\n")
  725     (write _test-input-stream "}\n")
  726     # convert
  727     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  728     (flush _test-output-buffered-file)
  729 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  735     # check output
  736     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  737     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  738     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  739     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  740     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  741     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  742     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  743     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  744     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  745     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  746     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  747     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  748     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  749     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  750     # . epilogue
  751     89/<- %esp 5/r32/ebp
  752     5d/pop-to-ebp
  753     c3/return
  754 
  755 test-convert-function-with-literal-arg:
  756     # . prologue
  757     55/push-ebp
  758     89/<- %ebp 4/r32/esp
  759     # setup
  760     (clear-stream _test-input-stream)
  761     (clear-stream $_test-input-buffered-file->buffer)
  762     (clear-stream _test-output-stream)
  763     (clear-stream $_test-output-buffered-file->buffer)
  764     #
  765     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  766     (write _test-input-stream "  result <- copy a\n")
  767     (write _test-input-stream "  result <- add 1\n")
  768     (write _test-input-stream "}\n")
  769     # convert
  770     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  771     (flush _test-output-buffered-file)
  772 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  778     # check output
  779     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  780     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  781     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  782     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  783     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  784     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  785     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  786     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  787     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  788     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  789     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  790     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  791     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  792     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  793     # . epilogue
  794     89/<- %esp 5/r32/ebp
  795     5d/pop-to-ebp
  796     c3/return
  797 
  798 test-convert-function-with-literal-arg-2:
  799     # . prologue
  800     55/push-ebp
  801     89/<- %ebp 4/r32/esp
  802     # setup
  803     (clear-stream _test-input-stream)
  804     (clear-stream $_test-input-buffered-file->buffer)
  805     (clear-stream _test-output-stream)
  806     (clear-stream $_test-output-buffered-file->buffer)
  807     #
  808     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  809     (write _test-input-stream "  result <- copy a\n")
  810     (write _test-input-stream "  result <- add 1\n")
  811     (write _test-input-stream "}\n")
  812     # convert
  813     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  814     (flush _test-output-buffered-file)
  815 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  821     # check output
  822     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  823     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  824     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  825     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  826     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  827     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  828     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  829     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  830     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  831     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  832     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  833     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  834     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  835     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  836     # . epilogue
  837     89/<- %esp 5/r32/ebp
  838     5d/pop-to-ebp
  839     c3/return
  840 
  841 test-convert-function-call-with-literal-arg:
  842     # . prologue
  843     55/push-ebp
  844     89/<- %ebp 4/r32/esp
  845     # setup
  846     (clear-stream _test-input-stream)
  847     (clear-stream $_test-input-buffered-file->buffer)
  848     (clear-stream _test-output-stream)
  849     (clear-stream $_test-output-buffered-file->buffer)
  850     #
  851     (write _test-input-stream "fn main -> result/ebx: int {\n")
  852     (write _test-input-stream "  result <- do-add 3 4\n")
  853     (write _test-input-stream "}\n")
  854     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  855     (write _test-input-stream "  result <- copy a\n")
  856     (write _test-input-stream "  result <- add b\n")
  857     (write _test-input-stream "}\n")
  858     # convert
  859     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  860     (flush _test-output-buffered-file)
  861 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  867     # check output
  868     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  869     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  870     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  871     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  872     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  873     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  874     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  875     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  876     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  877     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  878     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  879     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  880     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  881     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  882     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  883     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  884     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  885     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  886     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  887     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  888     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  889     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  890     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  891     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  892     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  893     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  894     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  895     # . epilogue
  896     89/<- %esp 5/r32/ebp
  897     5d/pop-to-ebp
  898     c3/return
  899 
  900 test-convert-function-with-local-var-in-mem:
  901     # . prologue
  902     55/push-ebp
  903     89/<- %ebp 4/r32/esp
  904     # setup
  905     (clear-stream _test-input-stream)
  906     (clear-stream $_test-input-buffered-file->buffer)
  907     (clear-stream _test-output-stream)
  908     (clear-stream $_test-output-buffered-file->buffer)
  909     #
  910     (write _test-input-stream "fn foo {\n")
  911     (write _test-input-stream "  var x: int\n")
  912     (write _test-input-stream "  increment x\n")
  913     (write _test-input-stream "}\n")
  914     # convert
  915     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  916     (flush _test-output-buffered-file)
  917 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  923     # check output
  924     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  925     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  926     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  927     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  928     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  930     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  931     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  932     (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")
  933     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  934     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  935     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  936     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  937     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  938     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  939     # . epilogue
  940     89/<- %esp 5/r32/ebp
  941     5d/pop-to-ebp
  942     c3/return
  943 
  944 test-local-var-in-mem-has-no-initializer:
  945     # . prologue
  946     55/push-ebp
  947     89/<- %ebp 4/r32/esp
  948     # setup
  949     (clear-stream _test-input-stream)
  950     (clear-stream $_test-input-buffered-file->buffer)
  951     (clear-stream _test-output-stream)
  952     (clear-stream $_test-output-buffered-file->buffer)
  953     (clear-stream _test-error-stream)
  954     (clear-stream $_test-error-buffered-file->buffer)
  955     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
  956     68/push 0/imm32
  957     68/push 0/imm32
  958     89/<- %edx 4/r32/esp
  959     (tailor-exit-descriptor %edx 0x10)
  960     #
  961     (write _test-input-stream "fn foo {\n")
  962     (write _test-input-stream "  var x: int <- copy 0\n")
  963     (write _test-input-stream "  increment x\n")
  964     (write _test-input-stream "}\n")
  965     # convert
  966     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
  967     # registers except esp clobbered at this point
  968     # restore ed
  969     89/<- %edx 4/r32/esp
  970     (flush _test-output-buffered-file)
  971     (flush _test-error-buffered-file)
  972 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
  978     # check output
  979     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
  980     (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")
  981     # check that stop(1) was called
  982     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
  983     # don't restore from ebp
  984     81 0/subop/add %esp 8/imm32
  985     # . epilogue
  986     5d/pop-to-ebp
  987     c3/return
  988 
  989 test-convert-function-with-local-var-with-compound-type-in-mem:
  990     # . prologue
  991     55/push-ebp
  992     89/<- %ebp 4/r32/esp
  993     # setup
  994     (clear-stream _test-input-stream)
  995     (clear-stream $_test-input-buffered-file->buffer)
  996     (clear-stream _test-output-stream)
  997     (clear-stream $_test-output-buffered-file->buffer)
  998     #
  999     (write _test-input-stream "fn foo {\n")
 1000     (write _test-input-stream "  var x: (addr int)\n")
 1001     (write _test-input-stream "  copy-to x, 0\n")
 1002     (write _test-input-stream "}\n")
 1003     # convert
 1004     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1005     (flush _test-output-buffered-file)
 1006 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1012     # check output
 1013     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1014     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1015     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1016     (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")
 1017     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1018     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1019     (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")
 1020     (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")
 1021     (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")
 1022     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1023     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1024     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1025     (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")
 1026     (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")
 1027     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1028     # . epilogue
 1029     89/<- %esp 5/r32/ebp
 1030     5d/pop-to-ebp
 1031     c3/return
 1032 
 1033 test-convert-function-with-local-var-in-reg:
 1034     # . prologue
 1035     55/push-ebp
 1036     89/<- %ebp 4/r32/esp
 1037     # setup
 1038     (clear-stream _test-input-stream)
 1039     (clear-stream $_test-input-buffered-file->buffer)
 1040     (clear-stream _test-output-stream)
 1041     (clear-stream $_test-output-buffered-file->buffer)
 1042     #
 1043     (write _test-input-stream "fn foo {\n")
 1044     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1045     (write _test-input-stream "  x <- increment\n")
 1046     (write _test-input-stream "}\n")
 1047     # convert
 1048     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1049     (flush _test-output-buffered-file)
 1050 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1056     # check output
 1057     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1058     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1059     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1060     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1061     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1062     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1063     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1064     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1065     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1066     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1067     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1069     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1070     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1071     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1072     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1073     # . epilogue
 1074     89/<- %esp 5/r32/ebp
 1075     5d/pop-to-ebp
 1076     c3/return
 1077 
 1078 test-convert-function-with-second-local-var-in-same-reg:
 1079     # . prologue
 1080     55/push-ebp
 1081     89/<- %ebp 4/r32/esp
 1082     # setup
 1083     (clear-stream _test-input-stream)
 1084     (clear-stream $_test-input-buffered-file->buffer)
 1085     (clear-stream _test-output-stream)
 1086     (clear-stream $_test-output-buffered-file->buffer)
 1087     #
 1088     (write _test-input-stream "fn foo {\n")
 1089     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1090     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1091     (write _test-input-stream "  y <- increment\n")
 1092     (write _test-input-stream "}\n")
 1093     # convert
 1094     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1095     (flush _test-output-buffered-file)
 1096 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1102     # check output
 1103     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1104     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1105     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1106     (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")
 1107     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1108     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1109     (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")
 1110     (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")
 1111     (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")
 1112     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1113     (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")
 1114     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1116     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1117     (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")
 1118     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1119     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1120     # . epilogue
 1121     89/<- %esp 5/r32/ebp
 1122     5d/pop-to-ebp
 1123     c3/return
 1124 
 1125 test-read-clobbered-reg-var:
 1126     # . prologue
 1127     55/push-ebp
 1128     89/<- %ebp 4/r32/esp
 1129     # setup
 1130     (clear-stream _test-input-stream)
 1131     (clear-stream $_test-input-buffered-file->buffer)
 1132     (clear-stream _test-output-stream)
 1133     (clear-stream $_test-output-buffered-file->buffer)
 1134     (clear-stream _test-error-stream)
 1135     (clear-stream $_test-error-buffered-file->buffer)
 1136     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1137     68/push 0/imm32
 1138     68/push 0/imm32
 1139     89/<- %edx 4/r32/esp
 1140     (tailor-exit-descriptor %edx 0x10)
 1141     #
 1142     (write _test-input-stream "fn foo {\n")
 1143     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1144     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1145     (write _test-input-stream "  x <- increment\n")
 1146     (write _test-input-stream "}\n")
 1147     # convert
 1148     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1149     # registers except esp clobbered at this point
 1150     # restore ed
 1151     89/<- %edx 4/r32/esp
 1152     (flush _test-output-buffered-file)
 1153     (flush _test-error-buffered-file)
 1154 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1160     # check output
 1161     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1162     (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")
 1163     # check that stop(1) was called
 1164     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1165     # don't restore from ebp
 1166     81 0/subop/add %esp 8/imm32
 1167     # . epilogue
 1168     5d/pop-to-ebp
 1169     c3/return
 1170 
 1171 test-convert-function-call:
 1172     # . prologue
 1173     55/push-ebp
 1174     89/<- %ebp 4/r32/esp
 1175     # setup
 1176     (clear-stream _test-input-stream)
 1177     (clear-stream $_test-input-buffered-file->buffer)
 1178     (clear-stream _test-output-stream)
 1179     (clear-stream $_test-output-buffered-file->buffer)
 1180     #
 1181     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1182     (write _test-input-stream "  result <- foo\n")
 1183     (write _test-input-stream "}\n")
 1184     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1185     (write _test-input-stream "  result <- copy 3\n")
 1186     (write _test-input-stream "}\n")
 1187     # convert
 1188     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1189     (flush _test-output-buffered-file)
 1190 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1196     # check output
 1197     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1198     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1199     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1200     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1201     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1202     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1203     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1204     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1205     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1206     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1207     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1208     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1209     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1210     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1211     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1212     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1213     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1214     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1215     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1216     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1217     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1219     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1220     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1221     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1222     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1223     # . epilogue
 1224     89/<- %esp 5/r32/ebp
 1225     5d/pop-to-ebp
 1226     c3/return
 1227 
 1228 test-convert-function-call-with-incorrect-inout-type:
 1229     # . prologue
 1230     55/push-ebp
 1231     89/<- %ebp 4/r32/esp
 1232     # setup
 1233     (clear-stream _test-input-stream)
 1234     (clear-stream $_test-input-buffered-file->buffer)
 1235     (clear-stream _test-output-stream)
 1236     (clear-stream $_test-output-buffered-file->buffer)
 1237     (clear-stream _test-error-stream)
 1238     (clear-stream $_test-error-buffered-file->buffer)
 1239     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1240     68/push 0/imm32
 1241     68/push 0/imm32
 1242     89/<- %edx 4/r32/esp
 1243     (tailor-exit-descriptor %edx 0x10)
 1244     #
 1245     (write _test-input-stream "fn f {\n")
 1246     (write _test-input-stream "  var x: int\n")
 1247     (write _test-input-stream "  g x\n")
 1248     (write _test-input-stream "}\n")
 1249     (write _test-input-stream "fn g a: foo {\n")
 1250     (write _test-input-stream "}\n")
 1251     # convert
 1252     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1253     # registers except esp clobbered at this point
 1254     # restore ed
 1255     89/<- %edx 4/r32/esp
 1256     (flush _test-output-buffered-file)
 1257     (flush _test-error-buffered-file)
 1258 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1264     # check output
 1265     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1266     (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")
 1267     # check that stop(1) was called
 1268     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1269     # don't restore from ebp
 1270     81 0/subop/add %esp 8/imm32
 1271     5d/pop-to-ebp
 1272     c3/return
 1273 
 1274 test-convert-function-call-with-too-few-inouts:
 1275     # . prologue
 1276     55/push-ebp
 1277     89/<- %ebp 4/r32/esp
 1278     # setup
 1279     (clear-stream _test-input-stream)
 1280     (clear-stream $_test-input-buffered-file->buffer)
 1281     (clear-stream _test-output-stream)
 1282     (clear-stream $_test-output-buffered-file->buffer)
 1283     (clear-stream _test-error-stream)
 1284     (clear-stream $_test-error-buffered-file->buffer)
 1285     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1286     68/push 0/imm32
 1287     68/push 0/imm32
 1288     89/<- %edx 4/r32/esp
 1289     (tailor-exit-descriptor %edx 0x10)
 1290     #
 1291     (write _test-input-stream "fn f {\n")
 1292     (write _test-input-stream "  g\n")
 1293     (write _test-input-stream "}\n")
 1294     (write _test-input-stream "fn g a: int {\n")
 1295     (write _test-input-stream "}\n")
 1296     # convert
 1297     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1298     # registers except esp clobbered at this point
 1299     # restore ed
 1300     89/<- %edx 4/r32/esp
 1301     (flush _test-output-buffered-file)
 1302     (flush _test-error-buffered-file)
 1303 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1309     # check output
 1310     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1311     (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")
 1312     # check that stop(1) was called
 1313     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1314     # don't restore from ebp
 1315     81 0/subop/add %esp 8/imm32
 1316     5d/pop-to-ebp
 1317     c3/return
 1318 
 1319 test-convert-function-call-with-too-many-inouts:
 1320     # . prologue
 1321     55/push-ebp
 1322     89/<- %ebp 4/r32/esp
 1323     # setup
 1324     (clear-stream _test-input-stream)
 1325     (clear-stream $_test-input-buffered-file->buffer)
 1326     (clear-stream _test-output-stream)
 1327     (clear-stream $_test-output-buffered-file->buffer)
 1328     (clear-stream _test-error-stream)
 1329     (clear-stream $_test-error-buffered-file->buffer)
 1330     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1331     68/push 0/imm32
 1332     68/push 0/imm32
 1333     89/<- %edx 4/r32/esp
 1334     (tailor-exit-descriptor %edx 0x10)
 1335     #
 1336     (write _test-input-stream "fn f {\n")
 1337     (write _test-input-stream "  var x: int\n")
 1338     (write _test-input-stream "  g x\n")
 1339     (write _test-input-stream "}\n")
 1340     (write _test-input-stream "fn g {\n")
 1341     (write _test-input-stream "}\n")
 1342     # convert
 1343     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1344     # registers except esp clobbered at this point
 1345     # restore ed
 1346     89/<- %edx 4/r32/esp
 1347     (flush _test-output-buffered-file)
 1348     (flush _test-error-buffered-file)
 1349 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1355     # check output
 1356     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1357     (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")
 1358     # check that stop(1) was called
 1359     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1360     # don't restore from ebp
 1361     81 0/subop/add %esp 8/imm32
 1362     5d/pop-to-ebp
 1363     c3/return
 1364 
 1365 test-convert-function-call-with-incorrect-output-type:
 1366     # . prologue
 1367     55/push-ebp
 1368     89/<- %ebp 4/r32/esp
 1369     # setup
 1370     (clear-stream _test-input-stream)
 1371     (clear-stream $_test-input-buffered-file->buffer)
 1372     (clear-stream _test-output-stream)
 1373     (clear-stream $_test-output-buffered-file->buffer)
 1374     (clear-stream _test-error-stream)
 1375     (clear-stream $_test-error-buffered-file->buffer)
 1376     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1377     68/push 0/imm32
 1378     68/push 0/imm32
 1379     89/<- %edx 4/r32/esp
 1380     (tailor-exit-descriptor %edx 0x10)
 1381     #
 1382     (write _test-input-stream "fn f {\n")
 1383     (write _test-input-stream "  var x/eax: int <- g\n")
 1384     (write _test-input-stream "}\n")
 1385     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1386     (write _test-input-stream "}\n")
 1387     # convert
 1388     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1389     # registers except esp clobbered at this point
 1390     # restore ed
 1391     89/<- %edx 4/r32/esp
 1392     (flush _test-output-buffered-file)
 1393     (flush _test-error-buffered-file)
 1394 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1400     # check output
 1401     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1402     (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")
 1403     # check that stop(1) was called
 1404     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1405     # don't restore from ebp
 1406     81 0/subop/add %esp 8/imm32
 1407     5d/pop-to-ebp
 1408     c3/return
 1409 
 1410 test-convert-function-call-with-too-few-outputs:
 1411     # . prologue
 1412     55/push-ebp
 1413     89/<- %ebp 4/r32/esp
 1414     # setup
 1415     (clear-stream _test-input-stream)
 1416     (clear-stream $_test-input-buffered-file->buffer)
 1417     (clear-stream _test-output-stream)
 1418     (clear-stream $_test-output-buffered-file->buffer)
 1419     (clear-stream _test-error-stream)
 1420     (clear-stream $_test-error-buffered-file->buffer)
 1421     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1422     68/push 0/imm32
 1423     68/push 0/imm32
 1424     89/<- %edx 4/r32/esp
 1425     (tailor-exit-descriptor %edx 0x10)
 1426     #
 1427     (write _test-input-stream "fn f {\n")
 1428     (write _test-input-stream "  g\n")
 1429     (write _test-input-stream "}\n")
 1430     (write _test-input-stream "fn g -> a/eax: int {\n")
 1431     (write _test-input-stream "}\n")
 1432     # convert
 1433     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1434     # registers except esp clobbered at this point
 1435     # restore ed
 1436     89/<- %edx 4/r32/esp
 1437     (flush _test-output-buffered-file)
 1438     (flush _test-error-buffered-file)
 1439 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1445     # check output
 1446     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1447     (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")
 1448     # check that stop(1) was called
 1449     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1450     # don't restore from ebp
 1451     81 0/subop/add %esp 8/imm32
 1452     5d/pop-to-ebp
 1453     c3/return
 1454 
 1455 test-convert-function-call-with-too-many-outputs:
 1456     # . prologue
 1457     55/push-ebp
 1458     89/<- %ebp 4/r32/esp
 1459     # setup
 1460     (clear-stream _test-input-stream)
 1461     (clear-stream $_test-input-buffered-file->buffer)
 1462     (clear-stream _test-output-stream)
 1463     (clear-stream $_test-output-buffered-file->buffer)
 1464     (clear-stream _test-error-stream)
 1465     (clear-stream $_test-error-buffered-file->buffer)
 1466     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1467     68/push 0/imm32
 1468     68/push 0/imm32
 1469     89/<- %edx 4/r32/esp
 1470     (tailor-exit-descriptor %edx 0x10)
 1471     #
 1472     (write _test-input-stream "fn f {\n")
 1473     (write _test-input-stream "  var x/eax: int <- g\n")
 1474     (write _test-input-stream "}\n")
 1475     (write _test-input-stream "fn g {\n")
 1476     (write _test-input-stream "}\n")
 1477     # convert
 1478     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1479     # registers except esp clobbered at this point
 1480     # restore ed
 1481     89/<- %edx 4/r32/esp
 1482     (flush _test-output-buffered-file)
 1483     (flush _test-error-buffered-file)
 1484 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1490     # check output
 1491     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1492     (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")
 1493     # check that stop(1) was called
 1494     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1495     # don't restore from ebp
 1496     81 0/subop/add %esp 8/imm32
 1497     5d/pop-to-ebp
 1498     c3/return
 1499 
 1500 test-convert-function-call-with-incorrect-output-register:
 1501     # . prologue
 1502     55/push-ebp
 1503     89/<- %ebp 4/r32/esp
 1504     # setup
 1505     (clear-stream _test-input-stream)
 1506     (clear-stream $_test-input-buffered-file->buffer)
 1507     (clear-stream _test-output-stream)
 1508     (clear-stream $_test-output-buffered-file->buffer)
 1509     (clear-stream _test-error-stream)
 1510     (clear-stream $_test-error-buffered-file->buffer)
 1511     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1512     68/push 0/imm32
 1513     68/push 0/imm32
 1514     89/<- %edx 4/r32/esp
 1515     (tailor-exit-descriptor %edx 0x10)
 1516     #
 1517     (write _test-input-stream "fn f {\n")
 1518     (write _test-input-stream "  var x/ecx: int <- g\n")
 1519     (write _test-input-stream "}\n")
 1520     (write _test-input-stream "fn g -> a/eax: int {\n")
 1521     (write _test-input-stream "}\n")
 1522     # convert
 1523     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1524     # registers except esp clobbered at this point
 1525     # restore ed
 1526     89/<- %edx 4/r32/esp
 1527     (flush _test-output-buffered-file)
 1528     (flush _test-error-buffered-file)
 1529 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1535     # check output
 1536     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1537     (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")
 1538     # check that stop(1) was called
 1539     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1540     # don't restore from ebp
 1541     81 0/subop/add %esp 8/imm32
 1542     5d/pop-to-ebp
 1543     c3/return
 1544 
 1545 test-convert-function-with-local-var-dereferenced:
 1546     # . prologue
 1547     55/push-ebp
 1548     89/<- %ebp 4/r32/esp
 1549     # setup
 1550     (clear-stream _test-input-stream)
 1551     (clear-stream $_test-input-buffered-file->buffer)
 1552     (clear-stream _test-output-stream)
 1553     (clear-stream $_test-output-buffered-file->buffer)
 1554     #
 1555     (write _test-input-stream "fn foo {\n")
 1556     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1557     (write _test-input-stream "  increment *x\n")
 1558     (write _test-input-stream "}\n")
 1559     # convert
 1560     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1561     (flush _test-output-buffered-file)
 1562 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1568     # check output
 1569     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1570     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1571     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1572     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1573     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1574     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1575     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1576     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1577     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1578     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1579     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1581     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1582     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1583     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1584     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1585     # . epilogue
 1586     89/<- %esp 5/r32/ebp
 1587     5d/pop-to-ebp
 1588     c3/return
 1589 
 1590 # variables of type 'byte' are not allowed on the stack
 1591 test-convert-function-with-byte-operations:
 1592     # . prologue
 1593     55/push-ebp
 1594     89/<- %ebp 4/r32/esp
 1595     # setup
 1596     (clear-stream _test-input-stream)
 1597     (clear-stream $_test-input-buffered-file->buffer)
 1598     (clear-stream _test-output-stream)
 1599     (clear-stream $_test-output-buffered-file->buffer)
 1600     #
 1601     (write _test-input-stream "fn foo {\n")
 1602     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 1603     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 1604     (write _test-input-stream "  y <- copy-byte x\n")
 1605     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 1606     (write _test-input-stream "  y <- copy-byte *z\n")
 1607     (write _test-input-stream "  copy-byte-to *z, x\n")
 1608     (write _test-input-stream "}\n")
 1609     # convert
 1610     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1611     (flush _test-output-buffered-file)
 1612 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1618     # check output
 1619     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 1620     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 1621     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 1622     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 1623     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 1624     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 1625     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 1626     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 1627     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 1628     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 1629     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 1630     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 1631     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 1632     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 1633     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 1634     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 1635     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 1636     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 1637     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 1638     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 1639     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 1640     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 1641     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 1642     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 1643     # . epilogue
 1644     89/<- %esp 5/r32/ebp
 1645     5d/pop-to-ebp
 1646     c3/return
 1647 
 1648 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 1649 test-copy-byte-var-from-fn-arg:
 1650     # . prologue
 1651     55/push-ebp
 1652     89/<- %ebp 4/r32/esp
 1653     # setup
 1654     (clear-stream _test-input-stream)
 1655     (clear-stream $_test-input-buffered-file->buffer)
 1656     (clear-stream _test-output-stream)
 1657     (clear-stream $_test-output-buffered-file->buffer)
 1658     #
 1659     (write _test-input-stream "fn foo x: byte, y: int {\n")
 1660     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 1661     (write _test-input-stream "  var b/eax: int <- copy y\n")
 1662     (write _test-input-stream "}\n")
 1663     # convert
 1664     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1665     (flush _test-output-buffered-file)
 1666 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1672     # check output
 1673     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 1674     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 1675     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 1676     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 1677     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 1678     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 1679     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 1680     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 1681     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 1682     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 1683     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 1684     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 1685     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 1686     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 1687     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 1688     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 1689     # . epilogue
 1690     89/<- %esp 5/r32/ebp
 1691     5d/pop-to-ebp
 1692     c3/return
 1693 
 1694 test-convert-compare-register-with-literal:
 1695     # . prologue
 1696     55/push-ebp
 1697     89/<- %ebp 4/r32/esp
 1698     # setup
 1699     (clear-stream _test-input-stream)
 1700     (clear-stream $_test-input-buffered-file->buffer)
 1701     (clear-stream _test-output-stream)
 1702     (clear-stream $_test-output-buffered-file->buffer)
 1703     #
 1704     (write _test-input-stream "fn foo {\n")
 1705     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1706     (write _test-input-stream "  compare x, 0\n")
 1707     (write _test-input-stream "}\n")
 1708     # convert
 1709     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1710     (flush _test-output-buffered-file)
 1711 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1717     # check output
 1718     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1719     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1720     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1721     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1722     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1723     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1724     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1725     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1726     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1727     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1728     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1729     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1730     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1731     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1732     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1733     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1734     # . epilogue
 1735     89/<- %esp 5/r32/ebp
 1736     5d/pop-to-ebp
 1737     c3/return
 1738 
 1739 test-unknown-variable:
 1740     # . prologue
 1741     55/push-ebp
 1742     89/<- %ebp 4/r32/esp
 1743     # setup
 1744     (clear-stream _test-input-stream)
 1745     (clear-stream $_test-input-buffered-file->buffer)
 1746     (clear-stream _test-output-stream)
 1747     (clear-stream $_test-output-buffered-file->buffer)
 1748     (clear-stream _test-error-stream)
 1749     (clear-stream $_test-error-buffered-file->buffer)
 1750     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1751     68/push 0/imm32
 1752     68/push 0/imm32
 1753     89/<- %edx 4/r32/esp
 1754     (tailor-exit-descriptor %edx 0x10)
 1755     #
 1756     (write _test-input-stream "fn foo {\n")
 1757     (write _test-input-stream "  compare x, 0\n")
 1758     (write _test-input-stream "}\n")
 1759     # convert
 1760     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1761     # registers except esp clobbered at this point
 1762     # restore ed
 1763     89/<- %edx 4/r32/esp
 1764     (flush _test-output-buffered-file)
 1765     (flush _test-error-buffered-file)
 1766 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1772     # check output
 1773     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 1774     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 1775     # check that stop(1) was called
 1776     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 1777     # don't restore from ebp
 1778     81 0/subop/add %esp 8/imm32
 1779     # . epilogue
 1780     5d/pop-to-ebp
 1781     c3/return
 1782 
 1783 test-convert-function-with-local-var-in-block:
 1784     # . prologue
 1785     55/push-ebp
 1786     89/<- %ebp 4/r32/esp
 1787     # setup
 1788     (clear-stream _test-input-stream)
 1789     (clear-stream $_test-input-buffered-file->buffer)
 1790     (clear-stream _test-output-stream)
 1791     (clear-stream $_test-output-buffered-file->buffer)
 1792     #
 1793     (write _test-input-stream "fn foo {\n")
 1794     (write _test-input-stream "  {\n")
 1795     (write _test-input-stream "    var x: int\n")
 1796     (write _test-input-stream "    increment x\n")
 1797     (write _test-input-stream "  }\n")
 1798     (write _test-input-stream "}\n")
 1799     # convert
 1800     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1801     (flush _test-output-buffered-file)
 1802 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1808     # check output
 1809     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1810     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1811     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1812     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1813     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1814     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1815     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1816     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1817     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1818     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1819     (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")
 1820     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1821     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1822     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1824     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1825     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1826     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1827     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1828     # . epilogue
 1829     89/<- %esp 5/r32/ebp
 1830     5d/pop-to-ebp
 1831     c3/return
 1832 
 1833 test-convert-function-with-local-var-in-named-block:
 1834     # . prologue
 1835     55/push-ebp
 1836     89/<- %ebp 4/r32/esp
 1837     # setup
 1838     (clear-stream _test-input-stream)
 1839     (clear-stream $_test-input-buffered-file->buffer)
 1840     (clear-stream _test-output-stream)
 1841     (clear-stream $_test-output-buffered-file->buffer)
 1842     #
 1843     (write _test-input-stream "fn foo {\n")
 1844     (write _test-input-stream "  $bar: {\n")
 1845     (write _test-input-stream "    var x: int\n")
 1846     (write _test-input-stream "    increment x\n")
 1847     (write _test-input-stream "  }\n")
 1848     (write _test-input-stream "}\n")
 1849     # convert
 1850     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1851     (flush _test-output-buffered-file)
 1852 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1858     # check output
 1859     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1860     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1861     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1862     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1863     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1864     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1865     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1866     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1867     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1868     (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")
 1869     (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")
 1870     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1871     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1872     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1873     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1874     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1875     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1876     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1877     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1878     # . epilogue
 1879     89/<- %esp 5/r32/ebp
 1880     5d/pop-to-ebp
 1881     c3/return
 1882 
 1883 test-unknown-variable-in-named-block:
 1884     # . prologue
 1885     55/push-ebp
 1886     89/<- %ebp 4/r32/esp
 1887     # setup
 1888     (clear-stream _test-input-stream)
 1889     (clear-stream $_test-input-buffered-file->buffer)
 1890     (clear-stream _test-output-stream)
 1891     (clear-stream $_test-output-buffered-file->buffer)
 1892     (clear-stream _test-error-stream)
 1893     (clear-stream $_test-error-buffered-file->buffer)
 1894     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1895     68/push 0/imm32
 1896     68/push 0/imm32
 1897     89/<- %edx 4/r32/esp
 1898     (tailor-exit-descriptor %edx 0x10)
 1899     #
 1900     (write _test-input-stream "fn foo {\n")
 1901     (write _test-input-stream "  $a: {\n")
 1902     (write _test-input-stream "    compare x, 0\n")
 1903     (write _test-input-stream "  }\n")
 1904     (write _test-input-stream "}\n")
 1905     # convert
 1906     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1907     # registers except esp clobbered at this point
 1908     # restore ed
 1909     89/<- %edx 4/r32/esp
 1910     (flush _test-output-buffered-file)
 1911     (flush _test-error-buffered-file)
 1912 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1918     # check output
 1919     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 1920     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 1921     # check that stop(1) was called
 1922     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 1923     # don't restore from ebp
 1924     81 0/subop/add %esp 8/imm32
 1925     # . epilogue
 1926     5d/pop-to-ebp
 1927     c3/return
 1928 
 1929 test-always-shadow-outermost-reg-vars-in-function:
 1930     # . prologue
 1931     55/push-ebp
 1932     89/<- %ebp 4/r32/esp
 1933     # setup
 1934     (clear-stream _test-input-stream)
 1935     (clear-stream $_test-input-buffered-file->buffer)
 1936     (clear-stream _test-output-stream)
 1937     (clear-stream $_test-output-buffered-file->buffer)
 1938     #
 1939     (write _test-input-stream "fn foo {\n")
 1940     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1941     (write _test-input-stream "}\n")
 1942     # convert
 1943     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1944     (flush _test-output-buffered-file)
 1945 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1951     # check output
 1952     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1953     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1954     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1955     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1956     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1957     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1958     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1959     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1960     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1961     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1962     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1963     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1964     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1965     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1966     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1967     # . epilogue
 1968     89/<- %esp 5/r32/ebp
 1969     5d/pop-to-ebp
 1970     c3/return
 1971 
 1972 _pending-test-clobber-dead-local:
 1973     # . prologue
 1974     55/push-ebp
 1975     89/<- %ebp 4/r32/esp
 1976     # setup
 1977     (clear-stream _test-input-stream)
 1978     (clear-stream $_test-input-buffered-file->buffer)
 1979     (clear-stream _test-output-stream)
 1980     (clear-stream $_test-output-buffered-file->buffer)
 1981     #
 1982     (write _test-input-stream "fn foo {\n")
 1983     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1984     (write _test-input-stream "  {\n")
 1985     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1986     (write _test-input-stream "  }\n")
 1987     (write _test-input-stream "}\n")
 1988     # convert
 1989     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1990     (flush _test-output-buffered-file)
 1991 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1997     # check output
 1998     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 1999     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2000     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2001     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2002     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2003     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2004     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2005     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2006     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2007     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2008     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2009     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2010     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2011     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2012     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2013     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2014     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2015     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2016     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2017     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2018     # . epilogue
 2019     89/<- %esp 5/r32/ebp
 2020     5d/pop-to-ebp
 2021     c3/return
 2022 
 2023 test-shadow-live-local:
 2024     # . prologue
 2025     55/push-ebp
 2026     89/<- %ebp 4/r32/esp
 2027     # setup
 2028     (clear-stream _test-input-stream)
 2029     (clear-stream $_test-input-buffered-file->buffer)
 2030     (clear-stream _test-output-stream)
 2031     (clear-stream $_test-output-buffered-file->buffer)
 2032     #
 2033     (write _test-input-stream "fn foo {\n")
 2034     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2035     (write _test-input-stream "  {\n")
 2036     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2037     (write _test-input-stream "  }\n")
 2038     (write _test-input-stream "  x <- increment\n")
 2039     (write _test-input-stream "}\n")
 2040     # convert
 2041     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2042     (flush _test-output-buffered-file)
 2043 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2049     # check output
 2050     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2051     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2052     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2053     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2054     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2055     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2056     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2057     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2058     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2059     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2060     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2061     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2062     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2063     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2064     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2065     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2066     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2067     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2069     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2070     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2071     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2072     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2073     # . epilogue
 2074     89/<- %esp 5/r32/ebp
 2075     5d/pop-to-ebp
 2076     c3/return
 2077 
 2078 test-shadow-name:
 2079     # . prologue
 2080     55/push-ebp
 2081     89/<- %ebp 4/r32/esp
 2082     # setup
 2083     (clear-stream _test-input-stream)
 2084     (clear-stream $_test-input-buffered-file->buffer)
 2085     (clear-stream _test-output-stream)
 2086     (clear-stream $_test-output-buffered-file->buffer)
 2087     #
 2088     (write _test-input-stream "fn foo {\n")
 2089     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2090     (write _test-input-stream "  {\n")
 2091     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2092     (write _test-input-stream "  }\n")
 2093     (write _test-input-stream "  x <- increment\n")
 2094     (write _test-input-stream "}\n")
 2095     # convert
 2096     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2097     (flush _test-output-buffered-file)
 2098 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2104     # check output
 2105     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2106     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2107     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2108     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2109     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2110     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2111     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2112     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2113     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2114     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2115     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2116     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2117     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2118     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2120     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2122     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2124     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2125     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2126     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2127     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2128     # . epilogue
 2129     89/<- %esp 5/r32/ebp
 2130     5d/pop-to-ebp
 2131     c3/return
 2132 
 2133 test-shadow-name-2:
 2134     # . prologue
 2135     55/push-ebp
 2136     89/<- %ebp 4/r32/esp
 2137     # setup
 2138     (clear-stream _test-input-stream)
 2139     (clear-stream $_test-input-buffered-file->buffer)
 2140     (clear-stream _test-output-stream)
 2141     (clear-stream $_test-output-buffered-file->buffer)
 2142     #
 2143     (write _test-input-stream "fn foo {\n")
 2144     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2145     (write _test-input-stream "  {\n")
 2146     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2147     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2148     (write _test-input-stream "  }\n")
 2149     (write _test-input-stream "  x <- increment\n")
 2150     (write _test-input-stream "}\n")
 2151     # convert
 2152     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2153     (flush _test-output-buffered-file)
 2154 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2160     # check output
 2161     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2162     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2163     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2164     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2165     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2167     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2168     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2169     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2170     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2171     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2172     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2173     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2174     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2175     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2176     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2177     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2178     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2179     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2180     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2181     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2182     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2183     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2184     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2185     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2186     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2187     # . epilogue
 2188     89/<- %esp 5/r32/ebp
 2189     5d/pop-to-ebp
 2190     c3/return
 2191 
 2192 test-do-not-spill-same-register-in-block:
 2193     # . prologue
 2194     55/push-ebp
 2195     89/<- %ebp 4/r32/esp
 2196     # setup
 2197     (clear-stream _test-input-stream)
 2198     (clear-stream $_test-input-buffered-file->buffer)
 2199     (clear-stream _test-output-stream)
 2200     (clear-stream $_test-output-buffered-file->buffer)
 2201     #
 2202     (write _test-input-stream "fn foo {\n")
 2203     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2204     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2205     (write _test-input-stream "  y <- increment\n")
 2206     (write _test-input-stream "}\n")
 2207     # convert
 2208     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2209     (flush _test-output-buffered-file)
 2210 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2216     # check output
 2217     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2218     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2219     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2220     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2221     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2222     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2223     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2224     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2225     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2226     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2227     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2228     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2229     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2230     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2231     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2232     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2233     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2234     # . epilogue
 2235     89/<- %esp 5/r32/ebp
 2236     5d/pop-to-ebp
 2237     c3/return
 2238 
 2239 test-spill-different-register-in-block:
 2240     # . prologue
 2241     55/push-ebp
 2242     89/<- %ebp 4/r32/esp
 2243     # setup
 2244     (clear-stream _test-input-stream)
 2245     (clear-stream $_test-input-buffered-file->buffer)
 2246     (clear-stream _test-output-stream)
 2247     (clear-stream $_test-output-buffered-file->buffer)
 2248     #
 2249     (write _test-input-stream "fn foo {\n")
 2250     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2251     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2252     (write _test-input-stream "  y <- increment\n")
 2253     (write _test-input-stream "}\n")
 2254     # convert
 2255     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2256     (flush _test-output-buffered-file)
 2257 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2263     # check output
 2264     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2265     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2266     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2267     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2268     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2270     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2271     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2272     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2273     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2274     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2275     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2276     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2277     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2278     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2279     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2280     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2281     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2282     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2283     # . epilogue
 2284     89/<- %esp 5/r32/ebp
 2285     5d/pop-to-ebp
 2286     c3/return
 2287 
 2288 test-shadow-live-output:
 2289     # . prologue
 2290     55/push-ebp
 2291     89/<- %ebp 4/r32/esp
 2292     # setup
 2293     (clear-stream _test-input-stream)
 2294     (clear-stream $_test-input-buffered-file->buffer)
 2295     (clear-stream _test-output-stream)
 2296     (clear-stream $_test-output-buffered-file->buffer)
 2297     #
 2298     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2299     (write _test-input-stream "  x <- copy 3\n")
 2300     (write _test-input-stream "  {\n")
 2301     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2302     (write _test-input-stream "  }\n")
 2303     (write _test-input-stream "  x <- increment\n")
 2304     (write _test-input-stream "}\n")
 2305     # convert
 2306     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2307     (flush _test-output-buffered-file)
 2308 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2314     # check output
 2315     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2316     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2317     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2318     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2319     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2320     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2321     (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
 2322     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2323     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2324     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2325     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2326     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2327     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2328     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2329     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2330     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2331     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2332     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2333     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2334     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2335     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2336     # . epilogue
 2337     89/<- %esp 5/r32/ebp
 2338     5d/pop-to-ebp
 2339     c3/return
 2340 
 2341 test-stmt-defines-output-in-same-register-as-inout:
 2342     # . prologue
 2343     55/push-ebp
 2344     89/<- %ebp 4/r32/esp
 2345     # setup
 2346     (clear-stream _test-input-stream)
 2347     (clear-stream $_test-input-buffered-file->buffer)
 2348     (clear-stream _test-output-stream)
 2349     (clear-stream $_test-output-buffered-file->buffer)
 2350     (clear-stream _test-error-stream)
 2351     (clear-stream $_test-error-buffered-file->buffer)
 2352     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2353     68/push 0/imm32
 2354     68/push 0/imm32
 2355     89/<- %edx 4/r32/esp
 2356     (tailor-exit-descriptor %edx 0x10)
 2357     #
 2358     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2359     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2360     (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
 2361     (write _test-input-stream "}\n")
 2362     # convert
 2363     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2364     # registers except esp clobbered at this point
 2365     # restore ed
 2366     89/<- %edx 4/r32/esp
 2367     (flush _test-output-buffered-file)
 2368     (flush _test-error-buffered-file)
 2369 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2375     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2376     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2377     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2378     # don't restore from ebp
 2379     81 0/subop/add %esp 8/imm32
 2380     # . epilogue
 2381     5d/pop-to-ebp
 2382     c3/return
 2383 
 2384 test-local-clobbered-by-fn-output:
 2385     # . prologue
 2386     55/push-ebp
 2387     89/<- %ebp 4/r32/esp
 2388     # setup
 2389     (clear-stream _test-input-stream)
 2390     (clear-stream $_test-input-buffered-file->buffer)
 2391     (clear-stream _test-output-stream)
 2392     (clear-stream $_test-output-buffered-file->buffer)
 2393     #
 2394     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2395     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2396     (write _test-input-stream "  x <- copy y\n")
 2397     (write _test-input-stream "}\n")
 2398     # convert
 2399     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2400     (flush _test-output-buffered-file)
 2401 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2407     # check output
 2408     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2409     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2410     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2411     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2412     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2413     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2414     (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
 2415     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2416     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2417     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2418     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2419     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2420     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2421     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2422     # . epilogue
 2423     89/<- %esp 5/r32/ebp
 2424     5d/pop-to-ebp
 2425     c3/return
 2426 
 2427 test-read-output:
 2428     # . prologue
 2429     55/push-ebp
 2430     89/<- %ebp 4/r32/esp
 2431     # setup
 2432     (clear-stream _test-input-stream)
 2433     (clear-stream $_test-input-buffered-file->buffer)
 2434     (clear-stream _test-output-stream)
 2435     (clear-stream $_test-output-buffered-file->buffer)
 2436     #
 2437     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2438     (write _test-input-stream "  x <- copy 0x34\n")
 2439     (write _test-input-stream "  compare x, 0x35\n")
 2440     (write _test-input-stream "}\n")
 2441     # convert
 2442     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2443     (flush _test-output-buffered-file)
 2444 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2450     # check output
 2451     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2452     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2453     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2454     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2455     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2456     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2457     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2458     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2459     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2460     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2461     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2462     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2463     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2464     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2465     # . epilogue
 2466     89/<- %esp 5/r32/ebp
 2467     5d/pop-to-ebp
 2468     c3/return
 2469 
 2470 test-fn-output-written-in-inner-block:
 2471     # . prologue
 2472     55/push-ebp
 2473     89/<- %ebp 4/r32/esp
 2474     # setup
 2475     (clear-stream _test-input-stream)
 2476     (clear-stream $_test-input-buffered-file->buffer)
 2477     (clear-stream _test-output-stream)
 2478     (clear-stream $_test-output-buffered-file->buffer)
 2479     #
 2480     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2481     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2482     (write _test-input-stream "  {\n")
 2483     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2484     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2485     (write _test-input-stream "  }\n")
 2486     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2487     (write _test-input-stream "}\n")
 2488     # convert
 2489     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2490     (flush _test-output-buffered-file)
 2491 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2497     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2498     # check output
 2499     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2500     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2501     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2502     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2503     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2504     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2505     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2506     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2507     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2508     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2509     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2510     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2511     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2512     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2513     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2514     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 2515     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 2516     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 2517     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 2518     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 2519     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 2520     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 2521     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 2522     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 2523     # . epilogue
 2524     89/<- %esp 5/r32/ebp
 2525     5d/pop-to-ebp
 2526     c3/return
 2527 
 2528 test-convert-function-with-branches-in-block:
 2529     # . prologue
 2530     55/push-ebp
 2531     89/<- %ebp 4/r32/esp
 2532     # setup
 2533     (clear-stream _test-input-stream)
 2534     (clear-stream $_test-input-buffered-file->buffer)
 2535     (clear-stream _test-output-stream)
 2536     (clear-stream $_test-output-buffered-file->buffer)
 2537     #
 2538     (write _test-input-stream "fn foo x: int {\n")
 2539     (write _test-input-stream "  {\n")
 2540     (write _test-input-stream "    break-if->=\n")
 2541     (write _test-input-stream "    loop-if-addr<\n")
 2542     (write _test-input-stream "    increment x\n")
 2543     (write _test-input-stream "    loop\n")
 2544     (write _test-input-stream "  }\n")
 2545     (write _test-input-stream "}\n")
 2546     # convert
 2547     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2548     (flush _test-output-buffered-file)
 2549 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2555     # check output
 2556     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2557     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2558     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2559     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 2560     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 2561     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 2562     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 2563     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 2564     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 2565     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 2566     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 2567     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 2568     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 2569     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 2570     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 2571     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 2572     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 2573     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 2574     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 2575     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 2576     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 2577     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 2578     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 2579     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 2580     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 2581     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 2582     # . epilogue
 2583     89/<- %esp 5/r32/ebp
 2584     5d/pop-to-ebp
 2585     c3/return
 2586 
 2587 test-convert-function-with-branches-in-named-block:
 2588     # . prologue
 2589     55/push-ebp
 2590     89/<- %ebp 4/r32/esp
 2591     # setup
 2592     (clear-stream _test-input-stream)
 2593     (clear-stream $_test-input-buffered-file->buffer)
 2594     (clear-stream _test-output-stream)
 2595     (clear-stream $_test-output-buffered-file->buffer)
 2596     #
 2597     (write _test-input-stream "fn foo x: int {\n")
 2598     (write _test-input-stream "  $bar: {\n")
 2599     (write _test-input-stream "    break-if->= $bar\n")
 2600     (write _test-input-stream "    loop-if-addr< $bar\n")
 2601     (write _test-input-stream "    increment x\n")
 2602     (write _test-input-stream "    loop\n")
 2603     (write _test-input-stream "  }\n")
 2604     (write _test-input-stream "}\n")
 2605     # convert
 2606     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2607     (flush _test-output-buffered-file)
 2608 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2614     # check output
 2615     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 2616     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 2617     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 2618     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 2619     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 2620     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 2621     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 2622     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 2623     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 2624     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 2625     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 2626     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 2627     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 2628     (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")
 2629     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 2630     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 2631     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 2632     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 2633     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 2634     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 2635     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 2636     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 2637     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 2638     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 2639     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 2640     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 2641     # . epilogue
 2642     89/<- %esp 5/r32/ebp
 2643     5d/pop-to-ebp
 2644     c3/return
 2645 
 2646 test-convert-function-with-var-in-nested-block:
 2647     # . prologue
 2648     55/push-ebp
 2649     89/<- %ebp 4/r32/esp
 2650     # setup
 2651     (clear-stream _test-input-stream)
 2652     (clear-stream $_test-input-buffered-file->buffer)
 2653     (clear-stream _test-output-stream)
 2654     (clear-stream $_test-output-buffered-file->buffer)
 2655     #
 2656     (write _test-input-stream "fn foo x: int {\n")
 2657     (write _test-input-stream "  {\n")
 2658     (write _test-input-stream "    {\n")
 2659     (write _test-input-stream "      var x: int\n")
 2660     (write _test-input-stream "      increment x\n")
 2661     (write _test-input-stream "    }\n")
 2662     (write _test-input-stream "  }\n")
 2663     (write _test-input-stream "}\n")
 2664     # convert
 2665     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2666     (flush _test-output-buffered-file)
 2667 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2673     # check output
 2674     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 2675     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 2676     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 2677     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 2678     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 2679     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 2680     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 2681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 2682     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 2683     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 2684     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 2685     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 2686     (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")
 2687     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 2688     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 2689     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 2690     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 2691     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 2692     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 2693     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 2694     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 2695     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 2696     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 2697     # . epilogue
 2698     89/<- %esp 5/r32/ebp
 2699     5d/pop-to-ebp
 2700     c3/return
 2701 
 2702 test-convert-function-with-multiple-vars-in-nested-blocks:
 2703     # . prologue
 2704     55/push-ebp
 2705     89/<- %ebp 4/r32/esp
 2706     # setup
 2707     (clear-stream _test-input-stream)
 2708     (clear-stream $_test-input-buffered-file->buffer)
 2709     (clear-stream _test-output-stream)
 2710     (clear-stream $_test-output-buffered-file->buffer)
 2711     #
 2712     (write _test-input-stream "fn foo x: int {\n")
 2713     (write _test-input-stream "  {\n")
 2714     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 2715     (write _test-input-stream "    {\n")
 2716     (write _test-input-stream "      var y: int\n")
 2717     (write _test-input-stream "      x <- add y\n")
 2718     (write _test-input-stream "    }\n")
 2719     (write _test-input-stream "  }\n")
 2720     (write _test-input-stream "}\n")
 2721     # convert
 2722     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2723     (flush _test-output-buffered-file)
 2724 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2730     # check output
 2731     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 2732     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 2733     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 2734     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 2735     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 2736     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 2737     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 2738     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 2739     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 2740     (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")
 2741     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 2742     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 2743     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 2744     (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")
 2745     (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")
 2746     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 2747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 2748     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 2749     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 2750     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 2751     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 2752     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 2753     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 2754     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 2755     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 2756     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 2757     # . epilogue
 2758     89/<- %esp 5/r32/ebp
 2759     5d/pop-to-ebp
 2760     c3/return
 2761 
 2762 test-convert-function-with-branches-and-local-vars:
 2763     # A conditional 'break' after a 'var' in a block is converted into a
 2764     # nested block that performs all necessary cleanup before jumping. This
 2765     # results in some ugly code duplication.
 2766     # . prologue
 2767     55/push-ebp
 2768     89/<- %ebp 4/r32/esp
 2769     # setup
 2770     (clear-stream _test-input-stream)
 2771     (clear-stream $_test-input-buffered-file->buffer)
 2772     (clear-stream _test-output-stream)
 2773     (clear-stream $_test-output-buffered-file->buffer)
 2774     #
 2775     (write _test-input-stream "fn foo {\n")
 2776     (write _test-input-stream "  {\n")
 2777     (write _test-input-stream "    var x: int\n")
 2778     (write _test-input-stream "    break-if->=\n")
 2779     (write _test-input-stream "    increment x\n")
 2780     (write _test-input-stream "  }\n")
 2781     (write _test-input-stream "}\n")
 2782     # convert
 2783     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2784     (flush _test-output-buffered-file)
 2785 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2791     # check output
 2792     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 2793     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 2794     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 2795     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 2796     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 2797     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 2798     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 2799     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 2800     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 2801     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 2802     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 2803     (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")
 2804     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 2805     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 2806     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 2807     (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")
 2808     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 2809     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 2810     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 2811     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 2812     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 2813     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 2814     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 2815     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 2816     # . epilogue
 2817     89/<- %esp 5/r32/ebp
 2818     5d/pop-to-ebp
 2819     c3/return
 2820 
 2821 test-convert-function-with-conditional-loops-and-local-vars:
 2822     # A conditional 'loop' after a 'var' in a block is converted into a nested
 2823     # block that performs all necessary cleanup before jumping. This results
 2824     # in some ugly code duplication.
 2825     # . prologue
 2826     55/push-ebp
 2827     89/<- %ebp 4/r32/esp
 2828     # setup
 2829     (clear-stream _test-input-stream)
 2830     (clear-stream $_test-input-buffered-file->buffer)
 2831     (clear-stream _test-output-stream)
 2832     (clear-stream $_test-output-buffered-file->buffer)
 2833     #
 2834     (write _test-input-stream "fn foo {\n")
 2835     (write _test-input-stream "  {\n")
 2836     (write _test-input-stream "    var x: int\n")
 2837     (write _test-input-stream "    loop-if->=\n")
 2838     (write _test-input-stream "    increment x\n")
 2839     (write _test-input-stream "  }\n")
 2840     (write _test-input-stream "}\n")
 2841     # convert
 2842     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2843     (flush _test-output-buffered-file)
 2844 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2850     # check output
 2851     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 2852     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 2853     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 2854     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 2855     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 2856     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 2857     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 2858     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 2859     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 2860     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 2861     (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")
 2862     (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")
 2863     (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")
 2864     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2865     (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")
 2866     (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")
 2867     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2868     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2869     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2870     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2871     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2872     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2873     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2874     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2875     # . epilogue
 2876     89/<- %esp 5/r32/ebp
 2877     5d/pop-to-ebp
 2878     c3/return
 2879 
 2880 test-convert-function-with-unconditional-loops-and-local-vars:
 2881     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2882     # regular block cleanup. Any instructions after 'loop' are dead and
 2883     # therefore skipped.
 2884     # . prologue
 2885     55/push-ebp
 2886     89/<- %ebp 4/r32/esp
 2887     # setup
 2888     (clear-stream _test-input-stream)
 2889     (clear-stream $_test-input-buffered-file->buffer)
 2890     (clear-stream _test-output-stream)
 2891     (clear-stream $_test-output-buffered-file->buffer)
 2892     #
 2893     (write _test-input-stream "fn foo {\n")
 2894     (write _test-input-stream "  {\n")
 2895     (write _test-input-stream "    var x: int\n")
 2896     (write _test-input-stream "    loop\n")
 2897     (write _test-input-stream "    increment x\n")
 2898     (write _test-input-stream "  }\n")
 2899     (write _test-input-stream "}\n")
 2900     # convert
 2901     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2902     (flush _test-output-buffered-file)
 2903 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2909     # check output
 2910     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2911     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2912     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2913     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2914     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2915     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2916     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2917     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2918     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2919     (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")
 2920     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2921     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2922     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2923     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2924     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2925     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2926     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2927     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2928     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2929     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2930     # . epilogue
 2931     89/<- %esp 5/r32/ebp
 2932     5d/pop-to-ebp
 2933     c3/return
 2934 
 2935 test-convert-function-with-branches-and-loops-and-local-vars:
 2936     # . prologue
 2937     55/push-ebp
 2938     89/<- %ebp 4/r32/esp
 2939     # setup
 2940     (clear-stream _test-input-stream)
 2941     (clear-stream $_test-input-buffered-file->buffer)
 2942     (clear-stream _test-output-stream)
 2943     (clear-stream $_test-output-buffered-file->buffer)
 2944     #
 2945     (write _test-input-stream "fn foo {\n")
 2946     (write _test-input-stream "  {\n")
 2947     (write _test-input-stream "    var x: int\n")
 2948     (write _test-input-stream "    break-if->=\n")
 2949     (write _test-input-stream "    increment x\n")
 2950     (write _test-input-stream "    loop\n")
 2951     (write _test-input-stream "  }\n")
 2952     (write _test-input-stream "}\n")
 2953     # convert
 2954     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2955     (flush _test-output-buffered-file)
 2956 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2962     # check output
 2963     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2964     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2965     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2966     (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")
 2967     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2968     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2969     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2970     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2971     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2972     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2973     (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")
 2974     (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")
 2975     (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")
 2976     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2977     (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")
 2978     (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")
 2979     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2980     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2981     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2982     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2983     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2984     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2985     (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")
 2986     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2987     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2988     # . epilogue
 2989     89/<- %esp 5/r32/ebp
 2990     5d/pop-to-ebp
 2991     c3/return
 2992 
 2993 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 2994     # . prologue
 2995     55/push-ebp
 2996     89/<- %ebp 4/r32/esp
 2997     # setup
 2998     (clear-stream _test-input-stream)
 2999     (clear-stream $_test-input-buffered-file->buffer)
 3000     (clear-stream _test-output-stream)
 3001     (clear-stream $_test-output-buffered-file->buffer)
 3002     #
 3003     (write _test-input-stream "fn foo {\n")
 3004     (write _test-input-stream "  a: {\n")
 3005     (write _test-input-stream "    var x: int\n")
 3006     (write _test-input-stream "    {\n")
 3007     (write _test-input-stream "      var y: int\n")
 3008     (write _test-input-stream "      break-if->= a\n")
 3009     (write _test-input-stream "      increment x\n")
 3010     (write _test-input-stream "      loop\n")
 3011     (write _test-input-stream "    }\n")
 3012     (write _test-input-stream "  }\n")
 3013     (write _test-input-stream "}\n")
 3014     # convert
 3015     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3016     (flush _test-output-buffered-file)
 3017 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3023     # check output
 3024     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3025     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3026     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3027     (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")
 3028     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3030     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3031     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3032     (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")
 3033     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3034     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3035     (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")
 3036     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3037     (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")
 3038     (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")
 3039     (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")
 3040     (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")
 3041     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3042     (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")
 3043     (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")
 3044     (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")
 3045     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3047     (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")
 3048     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3049     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3050     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3051     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3052     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3053     (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")
 3054     (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")
 3055     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3056     # . epilogue
 3057     89/<- %esp 5/r32/ebp
 3058     5d/pop-to-ebp
 3059     c3/return
 3060 
 3061 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3062     # . prologue
 3063     55/push-ebp
 3064     89/<- %ebp 4/r32/esp
 3065     # setup
 3066     (clear-stream _test-input-stream)
 3067     (clear-stream $_test-input-buffered-file->buffer)
 3068     (clear-stream _test-output-stream)
 3069     (clear-stream $_test-output-buffered-file->buffer)
 3070     # non-local conditional branch from a block without a local variable,
 3071     # unwinding a local on the stack
 3072     (write _test-input-stream "fn foo {\n")
 3073     (write _test-input-stream "  a: {\n")
 3074     (write _test-input-stream "    var x: int\n")
 3075     (write _test-input-stream "    {\n")
 3076     (write _test-input-stream "      break-if->= a\n")
 3077     (write _test-input-stream "    }\n")
 3078     (write _test-input-stream "  }\n")
 3079     (write _test-input-stream "}\n")
 3080     # convert
 3081     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3082     (flush _test-output-buffered-file)
 3083 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3089     # check output
 3090     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3091     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3092     (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")
 3093     (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")
 3094     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3095     (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")
 3096     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3097     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3098     (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")
 3099     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3100     (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")
 3101     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3102     (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")
 3103     (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")
 3104     (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")
 3105     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3106     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3107     (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")
 3108     (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")
 3109     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3110     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3111     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3112     (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")
 3113     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3114     (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")
 3115     (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")
 3116     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3117     # . epilogue
 3118     89/<- %esp 5/r32/ebp
 3119     5d/pop-to-ebp
 3120     c3/return
 3121 
 3122 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3123     # . prologue
 3124     55/push-ebp
 3125     89/<- %ebp 4/r32/esp
 3126     # setup
 3127     (clear-stream _test-input-stream)
 3128     (clear-stream $_test-input-buffered-file->buffer)
 3129     (clear-stream _test-output-stream)
 3130     (clear-stream $_test-output-buffered-file->buffer)
 3131     # non-local unconditional branch from a block without a local variable,
 3132     # unwinding a local on the stack
 3133     (write _test-input-stream "fn foo {\n")
 3134     (write _test-input-stream "  a: {\n")
 3135     (write _test-input-stream "    var x: int\n")
 3136     (write _test-input-stream "    {\n")
 3137     (write _test-input-stream "      break a\n")
 3138     (write _test-input-stream "    }\n")
 3139     (write _test-input-stream "  }\n")
 3140     (write _test-input-stream "}\n")
 3141     # convert
 3142     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3143     (flush _test-output-buffered-file)
 3144 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3150     # check output
 3151     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3152     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3153     (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")
 3154     (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")
 3155     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3156     (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")
 3157     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3158     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3159     (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")
 3160     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3161     (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")
 3162     (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")
 3163     (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")
 3164     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3165     (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")
 3166     (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")
 3167     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3168     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3169     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3170     (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")
 3171     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3172     (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")
 3173     (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")
 3174     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3175     # . epilogue
 3176     89/<- %esp 5/r32/ebp
 3177     5d/pop-to-ebp
 3178     c3/return
 3179 
 3180 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3181     # . prologue
 3182     55/push-ebp
 3183     89/<- %ebp 4/r32/esp
 3184     # setup
 3185     (clear-stream _test-input-stream)
 3186     (clear-stream $_test-input-buffered-file->buffer)
 3187     (clear-stream _test-output-stream)
 3188     (clear-stream $_test-output-buffered-file->buffer)
 3189     #
 3190     (write _test-input-stream "fn foo {\n")
 3191     (write _test-input-stream "  a: {\n")
 3192     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3193     (write _test-input-stream "    {\n")
 3194     (write _test-input-stream "      break a\n")
 3195     (write _test-input-stream "    }\n")
 3196     (write _test-input-stream "  }\n")
 3197     (write _test-input-stream "}\n")
 3198     # convert
 3199     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3200     (flush _test-output-buffered-file)
 3201 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3207     # check output
 3208     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3209     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3210     (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")
 3211     (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")
 3212     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3213     (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")
 3214     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3215     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3216     (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")
 3217     (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")
 3218     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3219     (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")
 3220     (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")
 3221     (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")
 3222     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3223     (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")
 3224     (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")
 3225     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3226     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3227     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3228     (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")
 3229     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3230     (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")
 3231     (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")
 3232     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3233     # . epilogue
 3234     89/<- %esp 5/r32/ebp
 3235     5d/pop-to-ebp
 3236     c3/return
 3237 
 3238 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3239     # . prologue
 3240     55/push-ebp
 3241     89/<- %ebp 4/r32/esp
 3242     # setup
 3243     (clear-stream _test-input-stream)
 3244     (clear-stream $_test-input-buffered-file->buffer)
 3245     (clear-stream _test-output-stream)
 3246     (clear-stream $_test-output-buffered-file->buffer)
 3247     #
 3248     (write _test-input-stream "fn foo {\n")
 3249     (write _test-input-stream "  a: {\n")
 3250     (write _test-input-stream "    var x: int\n")
 3251     (write _test-input-stream "    {\n")
 3252     (write _test-input-stream "      var y: int\n")
 3253     (write _test-input-stream "      break a\n")
 3254     (write _test-input-stream "      increment x\n")
 3255     (write _test-input-stream "    }\n")
 3256     (write _test-input-stream "  }\n")
 3257     (write _test-input-stream "}\n")
 3258     # convert
 3259     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3260     (flush _test-output-buffered-file)
 3261 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3267     # check output
 3268     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3269     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3270     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3271     (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")
 3272     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3273     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3274     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3275     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3276     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3277     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3278     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3279     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3280     (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")
 3281     (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")
 3282     (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")
 3283     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3284     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3285     (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")
 3286     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3287     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3288     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3289     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3290     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3291     (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")
 3292     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3293     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3294     # . epilogue
 3295     89/<- %esp 5/r32/ebp
 3296     5d/pop-to-ebp
 3297     c3/return
 3298 
 3299 test-convert-function-with-unconditional-break-and-local-vars:
 3300     # . prologue
 3301     55/push-ebp
 3302     89/<- %ebp 4/r32/esp
 3303     # setup
 3304     (clear-stream _test-input-stream)
 3305     (clear-stream $_test-input-buffered-file->buffer)
 3306     (clear-stream _test-output-stream)
 3307     (clear-stream $_test-output-buffered-file->buffer)
 3308     #
 3309     (write _test-input-stream "fn foo {\n")
 3310     (write _test-input-stream "  {\n")
 3311     (write _test-input-stream "    var x: int\n")
 3312     (write _test-input-stream "    {\n")
 3313     (write _test-input-stream "      var y: int\n")
 3314     (write _test-input-stream "      break\n")
 3315     (write _test-input-stream "      increment x\n")
 3316     (write _test-input-stream "    }\n")
 3317     (write _test-input-stream "  }\n")
 3318     (write _test-input-stream "}\n")
 3319     # convert
 3320     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3321     (flush _test-output-buffered-file)
 3322 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3328     # check output
 3329     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3330     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3331     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3332     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3333     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3334     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3335     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3336     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3337     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3338     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3339     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3340     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3341     (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")
 3342     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3343     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3344     (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")
 3345     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3346     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3347     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3348     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3349     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3350     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3351     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3352     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3353     # . epilogue
 3354     89/<- %esp 5/r32/ebp
 3355     5d/pop-to-ebp
 3356     c3/return
 3357 
 3358 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3359     # . prologue
 3360     55/push-ebp
 3361     89/<- %ebp 4/r32/esp
 3362     # setup
 3363     (clear-stream _test-input-stream)
 3364     (clear-stream $_test-input-buffered-file->buffer)
 3365     (clear-stream _test-output-stream)
 3366     (clear-stream $_test-output-buffered-file->buffer)
 3367     #
 3368     (write _test-input-stream "fn foo {\n")
 3369     (write _test-input-stream "  a: {\n")
 3370     (write _test-input-stream "    var x: int\n")
 3371     (write _test-input-stream "    {\n")
 3372     (write _test-input-stream "      var y: int\n")
 3373     (write _test-input-stream "      loop a\n")
 3374     (write _test-input-stream "      increment x\n")
 3375     (write _test-input-stream "    }\n")
 3376     (write _test-input-stream "  }\n")
 3377     (write _test-input-stream "}\n")
 3378     # convert
 3379     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3380     (flush _test-output-buffered-file)
 3381 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3387     # check output
 3388     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3389     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3390     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3391     (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")
 3392     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3393     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3394     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3395     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3396     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3397     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3398     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3399     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3400     (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")
 3401     (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")
 3402     (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")
 3403     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3404     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3405     (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")
 3406     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3407     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3408     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3409     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3410     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3411     (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")
 3412     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3413     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3414     # . epilogue
 3415     89/<- %esp 5/r32/ebp
 3416     5d/pop-to-ebp
 3417     c3/return
 3418 
 3419 test-convert-function-with-local-array-var-in-mem:
 3420     # . prologue
 3421     55/push-ebp
 3422     89/<- %ebp 4/r32/esp
 3423     # setup
 3424     (clear-stream _test-input-stream)
 3425     (clear-stream $_test-input-buffered-file->buffer)
 3426     (clear-stream _test-output-stream)
 3427     (clear-stream $_test-output-buffered-file->buffer)
 3428     #
 3429     (write _test-input-stream "fn foo {\n")
 3430     (write _test-input-stream "  var x: (array int 3)\n")
 3431     (write _test-input-stream "}\n")
 3432     # convert
 3433     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3434     (flush _test-output-buffered-file)
 3435 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3441     # check output
 3442     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3443     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3444     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3445     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3446     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3447     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3448     # define x
 3449     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3450     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3451     # reclaim x
 3452     (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")
 3453     #
 3454     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3455     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3456     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3457     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3458     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3459     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3460     # . epilogue
 3461     89/<- %esp 5/r32/ebp
 3462     5d/pop-to-ebp
 3463     c3/return
 3464 
 3465 # special-case for size(byte) when allocating array
 3466 test-convert-function-with-local-array-of-bytes-in-mem:
 3467     # . prologue
 3468     55/push-ebp
 3469     89/<- %ebp 4/r32/esp
 3470     # setup
 3471     (clear-stream _test-input-stream)
 3472     (clear-stream $_test-input-buffered-file->buffer)
 3473     (clear-stream _test-output-stream)
 3474     (clear-stream $_test-output-buffered-file->buffer)
 3475     #
 3476     (write _test-input-stream "fn foo {\n")
 3477     (write _test-input-stream "  var x: (array byte 3)\n")
 3478     (write _test-input-stream "}\n")
 3479     # convert
 3480     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3481     (flush _test-output-buffered-file)
 3482 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3488     # check output
 3489     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 3490     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 3491     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 3492     (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")
 3493     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 3494     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 3495     # define x
 3496     (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")
 3497     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 3498     # reclaim x
 3499     (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")
 3500     #
 3501     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 3502     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 3503     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 3504     (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")
 3505     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 3506     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 3507     # . epilogue
 3508     89/<- %esp 5/r32/ebp
 3509     5d/pop-to-ebp
 3510     c3/return
 3511 
 3512 test-convert-address:
 3513     # . prologue
 3514     55/push-ebp
 3515     89/<- %ebp 4/r32/esp
 3516     # setup
 3517     (clear-stream _test-input-stream)
 3518     (clear-stream $_test-input-buffered-file->buffer)
 3519     (clear-stream _test-output-stream)
 3520     (clear-stream $_test-output-buffered-file->buffer)
 3521     #
 3522     (write _test-input-stream "fn foo {\n")
 3523     (write _test-input-stream "  var a: int\n")
 3524     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 3525     (write _test-input-stream "}\n")
 3526     # convert
 3527     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3528     (flush _test-output-buffered-file)
 3529 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3535     # check output
 3536     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 3537     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 3538     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 3539     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 3540     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 3541     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 3542     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 3543     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 3544     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 3545     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 3546     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 3547     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 3548     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 3549     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 3550     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 3551     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 3552     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 3553     # . epilogue
 3554     89/<- %esp 5/r32/ebp
 3555     5d/pop-to-ebp
 3556     c3/return
 3557 
 3558 test-convert-length-of-array:
 3559     # . prologue
 3560     55/push-ebp
 3561     89/<- %ebp 4/r32/esp
 3562     # setup
 3563     (clear-stream _test-input-stream)
 3564     (clear-stream $_test-input-buffered-file->buffer)
 3565     (clear-stream _test-output-stream)
 3566     (clear-stream $_test-output-buffered-file->buffer)
 3567     #
 3568     (write _test-input-stream "fn foo a: (addr array int) {\n")
 3569     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 3570     (write _test-input-stream "  var c/eax: int <- length b\n")
 3571     (write _test-input-stream "}\n")
 3572     # convert
 3573     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3574     (flush _test-output-buffered-file)
 3575 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3581     # check output
 3582     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 3583     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 3584     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 3585     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 3586     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 3587     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 3588     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 3589     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 3590     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 3591     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 3592     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 3593     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 3594     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 3595     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 3596     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 3597     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 3598     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 3599     # . epilogue
 3600     89/<- %esp 5/r32/ebp
 3601     5d/pop-to-ebp
 3602     c3/return
 3603 
 3604 # special-case for size(byte) when computing array length
 3605 test-convert-length-of-array-of-bytes:
 3606     # . prologue
 3607     55/push-ebp
 3608     89/<- %ebp 4/r32/esp
 3609     # setup
 3610     (clear-stream _test-input-stream)
 3611     (clear-stream $_test-input-buffered-file->buffer)
 3612     (clear-stream _test-output-stream)
 3613     (clear-stream $_test-output-buffered-file->buffer)
 3614     #
 3615     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 3616     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 3617     (write _test-input-stream "  var c/eax: int <- length b\n")
 3618     (write _test-input-stream "}\n")
 3619     # convert
 3620     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3621     (flush _test-output-buffered-file)
 3622 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3628     # check output
 3629     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 3630     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 3631     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 3632     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 3633     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 3634     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 3635     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 3636     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 3637     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 3638     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 3639     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 3640     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 3641     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 3642     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 3643     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 3644     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 3645     # . epilogue
 3646     89/<- %esp 5/r32/ebp
 3647     5d/pop-to-ebp
 3648     c3/return
 3649 
 3650 test-convert-length-of-array-on-stack:
 3651     # . prologue
 3652     55/push-ebp
 3653     89/<- %ebp 4/r32/esp
 3654     # setup
 3655     (clear-stream _test-input-stream)
 3656     (clear-stream $_test-input-buffered-file->buffer)
 3657     (clear-stream _test-output-stream)
 3658     (clear-stream $_test-output-buffered-file->buffer)
 3659     #
 3660     (write _test-input-stream "fn foo {\n")
 3661     (write _test-input-stream "  var a: (array int 3)\n")
 3662     (write _test-input-stream "  var b/eax: int <- length a\n")
 3663     (write _test-input-stream "}\n")
 3664     # convert
 3665     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3666     (flush _test-output-buffered-file)
 3667 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3673     # check output
 3674     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 3675     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 3676     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 3677     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 3678     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 3679     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 3680     # define x
 3681     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 3682     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 3683     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 3684     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 3685     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 3686     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 3687     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 3688     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 3689     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 3690     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 3691     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 3692     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 3693     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 3694     # . epilogue
 3695     89/<- %esp 5/r32/ebp
 3696     5d/pop-to-ebp
 3697     c3/return
 3698 
 3699 test-reg-var-def-with-read-of-same-register:
 3700     # . prologue
 3701     55/push-ebp
 3702     89/<- %ebp 4/r32/esp
 3703     # setup
 3704     (clear-stream _test-input-stream)
 3705     (clear-stream $_test-input-buffered-file->buffer)
 3706     (clear-stream _test-output-stream)
 3707     (clear-stream $_test-output-buffered-file->buffer)
 3708     (clear-stream _test-error-stream)
 3709     (clear-stream $_test-error-buffered-file->buffer)
 3710     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 3711     68/push 0/imm32
 3712     68/push 0/imm32
 3713     89/<- %edx 4/r32/esp
 3714     (tailor-exit-descriptor %edx 0x10)
 3715     #
 3716     (write _test-input-stream "fn foo {\n")
 3717     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3718     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3719     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3720     (write _test-input-stream "}\n")
 3721     # convert
 3722     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3723     # registers except esp could be clobbered at this point (though they shouldn't be)
 3724     # restore ed
 3725     89/<- %edx 4/r32/esp
 3726     (flush _test-output-buffered-file)
 3727     (flush _test-error-buffered-file)
 3728 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3734     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 3735     # check output
 3736     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 3737     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 3738     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 3739     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 3740     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 3741     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 3742     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 3743     (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")
 3744     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 3745     (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")
 3746     (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")
 3747     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 3748     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 3749     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 3750     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 3751     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 3752     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 3753     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 3754     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 3755     # don't restore from ebp
 3756     81 0/subop/add %esp 8/imm32
 3757     # . epilogue
 3758     5d/pop-to-ebp
 3759     c3/return
 3760 
 3761 test-convert-index-into-array:
 3762     # . prologue
 3763     55/push-ebp
 3764     89/<- %ebp 4/r32/esp
 3765     # setup
 3766     (clear-stream _test-input-stream)
 3767     (clear-stream $_test-input-buffered-file->buffer)
 3768     (clear-stream _test-output-stream)
 3769     (clear-stream $_test-output-buffered-file->buffer)
 3770     #
 3771     (write _test-input-stream "fn foo {\n")
 3772     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3773     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3774     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3775     (write _test-input-stream "}\n")
 3776     # convert
 3777     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3778     (flush _test-output-buffered-file)
 3779 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3785     # check output
 3786     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 3787     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 3788     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 3789     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 3790     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 3791     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 3792     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 3793     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 3794     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 3795     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 3796     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 3797     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 3798     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 3799     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 3800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 3801     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 3802     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 3803     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 3804     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 3805     # . epilogue
 3806     89/<- %esp 5/r32/ebp
 3807     5d/pop-to-ebp
 3808     c3/return
 3809 
 3810 test-convert-index-into-array-of-bytes:
 3811     # . prologue
 3812     55/push-ebp
 3813     89/<- %ebp 4/r32/esp
 3814     # setup
 3815     (clear-stream _test-input-stream)
 3816     (clear-stream $_test-input-buffered-file->buffer)
 3817     (clear-stream _test-output-stream)
 3818     (clear-stream $_test-output-buffered-file->buffer)
 3819     #
 3820     (write _test-input-stream "fn foo {\n")
 3821     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3822     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3823     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 3824     (write _test-input-stream "}\n")
 3825     # convert
 3826     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3827     (flush _test-output-buffered-file)
 3828 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3834     # check output
 3835     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 3836     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 3837     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 3838     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 3839     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 3840     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 3841     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 3842     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 3843     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 3844     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 3845     (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")
 3846     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 3847     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 3848     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 3849     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 3850     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 3851     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 3852     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 3853     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 3854     # . epilogue
 3855     89/<- %esp 5/r32/ebp
 3856     5d/pop-to-ebp
 3857     c3/return
 3858 
 3859 test-convert-index-into-array-with-literal:
 3860     # . prologue
 3861     55/push-ebp
 3862     89/<- %ebp 4/r32/esp
 3863     # setup
 3864     (clear-stream _test-input-stream)
 3865     (clear-stream $_test-input-buffered-file->buffer)
 3866     (clear-stream _test-output-stream)
 3867     (clear-stream $_test-output-buffered-file->buffer)
 3868     #
 3869     (write _test-input-stream "fn foo {\n")
 3870     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3871     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3872     (write _test-input-stream "}\n")
 3873     # convert
 3874     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3875     (flush _test-output-buffered-file)
 3876 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3882     # check output
 3883     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 3884     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 3885     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 3886     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 3887     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 3888     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 3889     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 3890     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 3891                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 3892     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 3893     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 3894     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 3895     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 3896     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 3897     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 3898     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 3899     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 3900     # . epilogue
 3901     89/<- %esp 5/r32/ebp
 3902     5d/pop-to-ebp
 3903     c3/return
 3904 
 3905 test-convert-index-into-array-of-bytes-with-literal:
 3906     # . prologue
 3907     55/push-ebp
 3908     89/<- %ebp 4/r32/esp
 3909     # setup
 3910     (clear-stream _test-input-stream)
 3911     (clear-stream $_test-input-buffered-file->buffer)
 3912     (clear-stream _test-output-stream)
 3913     (clear-stream $_test-output-buffered-file->buffer)
 3914     #
 3915     (write _test-input-stream "fn foo {\n")
 3916     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3917     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 3918     (write _test-input-stream "}\n")
 3919     # convert
 3920     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3921     (flush _test-output-buffered-file)
 3922 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3928     # check output
 3929     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 3930     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 3931     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 3932     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 3933     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 3934     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 3935     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 3936     (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")
 3937                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 3938     (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")
 3939     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 3940     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 3941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 3942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 3943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 3944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 3945     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 3946     # . epilogue
 3947     89/<- %esp 5/r32/ebp
 3948     5d/pop-to-ebp
 3949     c3/return
 3950 
 3951 test-convert-index-into-array-on-stack:
 3952     # . prologue
 3953     55/push-ebp
 3954     89/<- %ebp 4/r32/esp
 3955     # setup
 3956     (clear-stream _test-input-stream)
 3957     (clear-stream $_test-input-buffered-file->buffer)
 3958     (clear-stream _test-output-stream)
 3959     (clear-stream $_test-output-buffered-file->buffer)
 3960     #
 3961     (write _test-input-stream "fn foo {\n")
 3962     (write _test-input-stream "  var arr: (array int 3)\n")
 3963     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 3964     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3965     (write _test-input-stream "}\n")
 3966     # convert
 3967     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3968     (flush _test-output-buffered-file)
 3969 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3975     # check output
 3976     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 3977     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 3978     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 3979     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 3980     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 3981     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 3982     # var arr
 3983     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 3984     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 3985     # var idx
 3986     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 3987     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 3988     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 3989     (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")
 3990     # reclaim idx
 3991     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 3992     # reclaim arr
 3993     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 3994     #
 3995     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 3996     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 3997     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 3998     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 3999     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4000     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4001     # . epilogue
 4002     89/<- %esp 5/r32/ebp
 4003     5d/pop-to-ebp
 4004     c3/return
 4005 
 4006 test-convert-index-into-array-on-stack-with-literal:
 4007     # . prologue
 4008     55/push-ebp
 4009     89/<- %ebp 4/r32/esp
 4010     # setup
 4011     (clear-stream _test-input-stream)
 4012     (clear-stream $_test-input-buffered-file->buffer)
 4013     (clear-stream _test-output-stream)
 4014     (clear-stream $_test-output-buffered-file->buffer)
 4015     #
 4016     (write _test-input-stream "fn foo {\n")
 4017     (write _test-input-stream "  var arr: (array int 3)\n")
 4018     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4019     (write _test-input-stream "}\n")
 4020     # convert
 4021     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4022     (flush _test-output-buffered-file)
 4023 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4029     # check output
 4030     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4031     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4032     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4033     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4034     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4035     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4036     # var arr
 4037     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4038     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4039     # var x
 4040     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4041     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4042     (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")
 4043     # reclaim x
 4044     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4045     # reclaim arr
 4046     (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")
 4047     #
 4048     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4049     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4050     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4051     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4052     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4053     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4054     # . epilogue
 4055     89/<- %esp 5/r32/ebp
 4056     5d/pop-to-ebp
 4057     c3/return
 4058 
 4059 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4060     # . prologue
 4061     55/push-ebp
 4062     89/<- %ebp 4/r32/esp
 4063     # setup
 4064     (clear-stream _test-input-stream)
 4065     (clear-stream $_test-input-buffered-file->buffer)
 4066     (clear-stream _test-output-stream)
 4067     (clear-stream $_test-output-buffered-file->buffer)
 4068     #
 4069     (write _test-input-stream "fn foo {\n")
 4070     (write _test-input-stream "  var arr: (array byte 3)\n")
 4071     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4072     (write _test-input-stream "}\n")
 4073     # convert
 4074     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4075     (flush _test-output-buffered-file)
 4076 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4082     # check output
 4083     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4084     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4085     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4086     (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")
 4087     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4088     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4089     # var arr
 4090     (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")
 4091     (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")
 4092     # var x
 4093     (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")
 4094     # x is at (ebp-7) + 4 + 2 = ebp-1
 4095     (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")
 4096     # reclaim x
 4097     (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")
 4098     # reclaim arr
 4099     (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")
 4100     #
 4101     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4102     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4103     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4104     (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")
 4105     (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")
 4106     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4107     # . epilogue
 4108     89/<- %esp 5/r32/ebp
 4109     5d/pop-to-ebp
 4110     c3/return
 4111 
 4112 test-convert-index-into-array-using-offset:
 4113     # . prologue
 4114     55/push-ebp
 4115     89/<- %ebp 4/r32/esp
 4116     # setup
 4117     (clear-stream _test-input-stream)
 4118     (clear-stream $_test-input-buffered-file->buffer)
 4119     (clear-stream _test-output-stream)
 4120     (clear-stream $_test-output-buffered-file->buffer)
 4121     #
 4122     (write _test-input-stream "fn foo {\n")
 4123     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4124     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4125     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4126     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4127     (write _test-input-stream "}\n")
 4128     # convert
 4129     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4130     (flush _test-output-buffered-file)
 4131 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4137     # check output
 4138     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4139     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4140     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4141     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4142     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4143     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4144     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4145     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4146     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4147     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4148     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4149     (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")
 4150     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4151     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4152     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4153     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4154     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4155     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4156     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4157     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4158     # . epilogue
 4159     89/<- %esp 5/r32/ebp
 4160     5d/pop-to-ebp
 4161     c3/return
 4162 
 4163 test-convert-index-into-array-of-bytes-using-offset:
 4164     # . prologue
 4165     55/push-ebp
 4166     89/<- %ebp 4/r32/esp
 4167     # setup
 4168     (clear-stream _test-input-stream)
 4169     (clear-stream $_test-input-buffered-file->buffer)
 4170     (clear-stream _test-output-stream)
 4171     (clear-stream $_test-output-buffered-file->buffer)
 4172     #
 4173     (write _test-input-stream "fn foo {\n")
 4174     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4175     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4176     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4177     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4178     (write _test-input-stream "}\n")
 4179     # convert
 4180     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4181     (flush _test-output-buffered-file)
 4182 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4188     # check output
 4189     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4190     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4191     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4192     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4193     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4194     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4195     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4196     (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")
 4197     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4198     (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")
 4199     (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")
 4200     (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")
 4201     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4202     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4203     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4204     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4205     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4206     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4207     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4208     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4209     # . epilogue
 4210     89/<- %esp 5/r32/ebp
 4211     5d/pop-to-ebp
 4212     c3/return
 4213 
 4214 test-convert-index-into-array-using-offset-on-stack:
 4215     # . prologue
 4216     55/push-ebp
 4217     89/<- %ebp 4/r32/esp
 4218     # setup
 4219     (clear-stream _test-input-stream)
 4220     (clear-stream $_test-input-buffered-file->buffer)
 4221     (clear-stream _test-output-stream)
 4222     (clear-stream $_test-output-buffered-file->buffer)
 4223     #
 4224     (write _test-input-stream "fn foo {\n")
 4225     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4226     (write _test-input-stream "  var idx: int\n")
 4227     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4228     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4229     (write _test-input-stream "}\n")
 4230     # convert
 4231     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4232     (flush _test-output-buffered-file)
 4233 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4239     # check output
 4240     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4241     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4242     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4243     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4244     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4245     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4246     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4247     (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")
 4248     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4249     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4250     (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")
 4251     (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")
 4252     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4253     (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")
 4254     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4255     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4256     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4257     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4258     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4259     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4260     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4261     # . epilogue
 4262     89/<- %esp 5/r32/ebp
 4263     5d/pop-to-ebp
 4264     c3/return
 4265 
 4266 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4267     # . prologue
 4268     55/push-ebp
 4269     89/<- %ebp 4/r32/esp
 4270     # setup
 4271     (clear-stream _test-input-stream)
 4272     (clear-stream $_test-input-buffered-file->buffer)
 4273     (clear-stream _test-output-stream)
 4274     (clear-stream $_test-output-buffered-file->buffer)
 4275     #
 4276     (write _test-input-stream "fn foo {\n")
 4277     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4278     (write _test-input-stream "  var idx: int\n")
 4279     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4280     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4281     (write _test-input-stream "}\n")
 4282     # convert
 4283     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4284     (flush _test-output-buffered-file)
 4285 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4291     # check output
 4292     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4293     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4294     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4295     (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")
 4296     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4297     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4298     (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")
 4299     (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")
 4300     (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")
 4301     (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")
 4302     (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")
 4303     (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")
 4304     (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")
 4305     (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")
 4306     (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")
 4307     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4308     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4309     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4310     (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")
 4311     (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")
 4312     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4313     # . epilogue
 4314     89/<- %esp 5/r32/ebp
 4315     5d/pop-to-ebp
 4316     c3/return
 4317 
 4318 test-convert-function-and-type-definition:
 4319     # . prologue
 4320     55/push-ebp
 4321     89/<- %ebp 4/r32/esp
 4322     # setup
 4323     (clear-stream _test-input-stream)
 4324     (clear-stream $_test-input-buffered-file->buffer)
 4325     (clear-stream _test-output-stream)
 4326     (clear-stream $_test-output-buffered-file->buffer)
 4327     #
 4328     (write _test-input-stream "fn foo a: (addr t) {\n")
 4329     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4330     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4331     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4332     (write _test-input-stream "}\n")
 4333     (write _test-input-stream "type t {\n")
 4334     (write _test-input-stream "  x: int\n")
 4335     (write _test-input-stream "  y: int\n")
 4336     (write _test-input-stream "}\n")
 4337     # convert
 4338     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4339     (flush _test-output-buffered-file)
 4340 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4346     # check output
 4347     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4348     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4349     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4350     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4351     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4352     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4353     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4354     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4355     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4356     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4357     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4358     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4359     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4360     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4361     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4362     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4363     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4364     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4365     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4366     # . epilogue
 4367     89/<- %esp 5/r32/ebp
 4368     5d/pop-to-ebp
 4369     c3/return
 4370 
 4371 test-convert-function-with-local-var-with-user-defined-type:
 4372     # . prologue
 4373     55/push-ebp
 4374     89/<- %ebp 4/r32/esp
 4375     # setup
 4376     (clear-stream _test-input-stream)
 4377     (clear-stream $_test-input-buffered-file->buffer)
 4378     (clear-stream _test-output-stream)
 4379     (clear-stream $_test-output-buffered-file->buffer)
 4380     #
 4381     (write _test-input-stream "fn foo {\n")
 4382     (write _test-input-stream "  var a: t\n")
 4383     (write _test-input-stream "}\n")
 4384     (write _test-input-stream "type t {\n")
 4385     (write _test-input-stream "  x: int\n")
 4386     (write _test-input-stream "  y: int\n")
 4387     (write _test-input-stream "}\n")
 4388     # convert
 4389     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4390     (flush _test-output-buffered-file)
 4391 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4397     # check output
 4398     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 4399     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 4400     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 4401     (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")
 4402     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 4403     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 4404     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 4405     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 4406     (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")
 4407     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 4408     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 4409     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 4410     (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")
 4411     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 4412     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 4413     # . epilogue
 4414     89/<- %esp 5/r32/ebp
 4415     5d/pop-to-ebp
 4416     c3/return
 4417 
 4418 test-convert-function-call-with-arg-of-user-defined-type:
 4419     # . prologue
 4420     55/push-ebp
 4421     89/<- %ebp 4/r32/esp
 4422     # setup
 4423     (clear-stream _test-input-stream)
 4424     (clear-stream $_test-input-buffered-file->buffer)
 4425     (clear-stream _test-output-stream)
 4426     (clear-stream $_test-output-buffered-file->buffer)
 4427     #
 4428     (write _test-input-stream "fn f {\n")
 4429     (write _test-input-stream "  var a: t\n")
 4430     (write _test-input-stream "  foo a\n")
 4431     (write _test-input-stream "}\n")
 4432     (write _test-input-stream "fn foo x: t {\n")
 4433     (write _test-input-stream "}\n")
 4434     (write _test-input-stream "type t {\n")
 4435     (write _test-input-stream "  x: int\n")
 4436     (write _test-input-stream "  y: int\n")
 4437     (write _test-input-stream "}\n")
 4438     # convert
 4439     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4440     (flush _test-output-buffered-file)
 4441 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4447     # check output
 4448     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4449     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4450     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4451     (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")
 4452     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4453     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4454     # var a: t
 4455     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 4456     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 4457     # foo a
 4458     (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")
 4459     #
 4460     (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")
 4461     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4462     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4463     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4464     (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")
 4465     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4466     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4467     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4468     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4469     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4470     (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")
 4471     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4472     (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")
 4473     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4474     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4475     # . epilogue
 4476     89/<- %esp 5/r32/ebp
 4477     5d/pop-to-ebp
 4478     c3/return
 4479 
 4480 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 4481     # . prologue
 4482     55/push-ebp
 4483     89/<- %ebp 4/r32/esp
 4484     # setup
 4485     (clear-stream _test-input-stream)
 4486     (clear-stream $_test-input-buffered-file->buffer)
 4487     (clear-stream _test-output-stream)
 4488     (clear-stream $_test-output-buffered-file->buffer)
 4489     #
 4490     (write _test-input-stream "fn f {\n")
 4491     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 4492     (write _test-input-stream "  foo *a\n")
 4493     (write _test-input-stream "}\n")
 4494     (write _test-input-stream "fn foo x: t {\n")
 4495     (write _test-input-stream "}\n")
 4496     (write _test-input-stream "type t {\n")
 4497     (write _test-input-stream "  x: int\n")
 4498     (write _test-input-stream "  y: int\n")
 4499     (write _test-input-stream "}\n")
 4500     # convert
 4501     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4502     (flush _test-output-buffered-file)
 4503 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4509     # check output
 4510     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4511     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4512     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4513     (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")
 4514     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4515     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4516     # var a
 4517     (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")
 4518     (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")
 4519     # foo a
 4520     (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")
 4521     #
 4522     (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")
 4523     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4524     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4525     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4526     (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")
 4527     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4528     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4529     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4530     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4531     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4532     (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")
 4533     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4534     (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")
 4535     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4536     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4537     # . epilogue
 4538     89/<- %esp 5/r32/ebp
 4539     5d/pop-to-ebp
 4540     c3/return
 4541 
 4542 # we don't have special support for call-by-reference; just explicitly create
 4543 # a new variable with the address of the arg
 4544 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 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 f {\n")
 4555     (write _test-input-stream "  var a: t\n")
 4556     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 4557     (write _test-input-stream "  foo b\n")
 4558     (write _test-input-stream "}\n")
 4559     (write _test-input-stream "fn foo x: (addr t) {\n")
 4560     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 4561     (write _test-input-stream "  increment *x\n")
 4562     (write _test-input-stream "}\n")
 4563     (write _test-input-stream "type t {\n")
 4564     (write _test-input-stream "  x: int\n")
 4565     (write _test-input-stream "  y: int\n")
 4566     (write _test-input-stream "}\n")
 4567     # convert
 4568     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4569     (flush _test-output-buffered-file)
 4570 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4576     # check output
 4577     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 4578     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 4579     (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")
 4580     (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")
 4581     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 4582     (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")
 4583     # var a: t
 4584     (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")
 4585     (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")
 4586     # var b/eax: (addr t)
 4587     (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")
 4588     (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")
 4589     # foo a
 4590     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 4591     #
 4592     (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")
 4593     (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")
 4594     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 4595     (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")
 4596     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 4597     (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")
 4598     (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")
 4599     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 4600     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 4601     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 4602     (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")
 4603     (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")
 4604     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 4605     (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")
 4606     (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")
 4607     (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")
 4608     (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")
 4609     (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")
 4610     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 4611     (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")
 4612     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 4613     (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")
 4614     (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")
 4615     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 4616     # . epilogue
 4617     89/<- %esp 5/r32/ebp
 4618     5d/pop-to-ebp
 4619     c3/return
 4620 
 4621 test-convert-get-on-local-variable:
 4622     # . prologue
 4623     55/push-ebp
 4624     89/<- %ebp 4/r32/esp
 4625     # setup
 4626     (clear-stream _test-input-stream)
 4627     (clear-stream $_test-input-buffered-file->buffer)
 4628     (clear-stream _test-output-stream)
 4629     (clear-stream $_test-output-buffered-file->buffer)
 4630     #
 4631     (write _test-input-stream "fn foo {\n")
 4632     (write _test-input-stream "  var a: t\n")
 4633     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4634     (write _test-input-stream "}\n")
 4635     (write _test-input-stream "type t {\n")
 4636     (write _test-input-stream "  x: int\n")
 4637     (write _test-input-stream "  y: int\n")
 4638     (write _test-input-stream "}\n")
 4639     # convert
 4640     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4641     (flush _test-output-buffered-file)
 4642 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4648     # check output
 4649     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 4650     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 4651     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 4652     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 4653     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 4654     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 4655     # var a
 4656     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 4657     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 4658     # var c
 4659     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 4660     # get
 4661     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 4662     # reclaim c
 4663     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 4664     # reclaim a
 4665     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 4666     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 4667     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 4668     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 4669     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 4670     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 4671     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 4672     # . epilogue
 4673     89/<- %esp 5/r32/ebp
 4674     5d/pop-to-ebp
 4675     c3/return
 4676 
 4677 test-convert-get-on-function-argument:
 4678     # . prologue
 4679     55/push-ebp
 4680     89/<- %ebp 4/r32/esp
 4681     # setup
 4682     (clear-stream _test-input-stream)
 4683     (clear-stream $_test-input-buffered-file->buffer)
 4684     (clear-stream _test-output-stream)
 4685     (clear-stream $_test-output-buffered-file->buffer)
 4686     #
 4687     (write _test-input-stream "fn foo a: t {\n")
 4688     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4689     (write _test-input-stream "}\n")
 4690     (write _test-input-stream "type t {\n")
 4691     (write _test-input-stream "  x: int\n")
 4692     (write _test-input-stream "  y: int\n")
 4693     (write _test-input-stream "}\n")
 4694     # convert
 4695     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4696     (flush _test-output-buffered-file)
 4697 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4703     # check output
 4704     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 4705     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 4706     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 4707     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 4708     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 4709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 4710     # var c
 4711     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 4712     # get
 4713     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 4714     # reclaim c
 4715     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 4716     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 4717     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 4718     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 4719     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 4720     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 4721     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 4722     # . epilogue
 4723     89/<- %esp 5/r32/ebp
 4724     5d/pop-to-ebp
 4725     c3/return
 4726 
 4727 test-convert-get-on-function-argument-with-known-type:
 4728     # . prologue
 4729     55/push-ebp
 4730     89/<- %ebp 4/r32/esp
 4731     # setup
 4732     (clear-stream _test-input-stream)
 4733     (clear-stream $_test-input-buffered-file->buffer)
 4734     (clear-stream _test-output-stream)
 4735     (clear-stream $_test-output-buffered-file->buffer)
 4736     #
 4737     (write _test-input-stream "type t {\n")
 4738     (write _test-input-stream "  x: int\n")
 4739     (write _test-input-stream "  y: int\n")
 4740     (write _test-input-stream "}\n")
 4741     (write _test-input-stream "fn foo a: t {\n")
 4742     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4743     (write _test-input-stream "}\n")
 4744     # convert
 4745     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4746     (flush _test-output-buffered-file)
 4747 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4753     # check output
 4754     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 4755     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 4756     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 4757     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 4758     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 4759     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 4760     # var c
 4761     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 4762     # get
 4763     (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")
 4764     # reclaim c
 4765     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 4766     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 4767     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 4768     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 4769     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 4770     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 4771     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 4772     # . epilogue
 4773     89/<- %esp 5/r32/ebp
 4774     5d/pop-to-ebp
 4775     c3/return
 4776 
 4777 test-get-with-wrong-field:
 4778     # . prologue
 4779     55/push-ebp
 4780     89/<- %ebp 4/r32/esp
 4781     # setup
 4782     (clear-stream _test-input-stream)
 4783     (clear-stream $_test-input-buffered-file->buffer)
 4784     (clear-stream _test-output-stream)
 4785     (clear-stream $_test-output-buffered-file->buffer)
 4786     (clear-stream _test-error-stream)
 4787     (clear-stream $_test-error-buffered-file->buffer)
 4788     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4789     68/push 0/imm32
 4790     68/push 0/imm32
 4791     89/<- %edx 4/r32/esp
 4792     (tailor-exit-descriptor %edx 0x10)
 4793     #
 4794     (write _test-input-stream "fn foo {\n")
 4795     (write _test-input-stream "  var a: t\n")
 4796     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4797     (write _test-input-stream "}\n")
 4798     (write _test-input-stream "type t {\n")
 4799     (write _test-input-stream "  x: int\n")
 4800     (write _test-input-stream "}\n")
 4801     # convert
 4802     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4803     # registers except esp clobbered at this point
 4804     # restore ed
 4805     89/<- %edx 4/r32/esp
 4806     (flush _test-output-buffered-file)
 4807     (flush _test-error-buffered-file)
 4808 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4814     # check output
 4815     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 4816     (check-next-stream-line-equal _test-error-stream  "type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
 4817     # check that stop(1) was called
 4818     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 4819     # don't restore from ebp
 4820     81 0/subop/add %esp 8/imm32
 4821     # . epilogue
 4822     5d/pop-to-ebp
 4823     c3/return
 4824 
 4825 test-convert-array-of-user-defined-types:
 4826     # . prologue
 4827     55/push-ebp
 4828     89/<- %ebp 4/r32/esp
 4829     # setup
 4830     (clear-stream _test-input-stream)
 4831     (clear-stream $_test-input-buffered-file->buffer)
 4832     (clear-stream _test-output-stream)
 4833     (clear-stream $_test-output-buffered-file->buffer)
 4834     #
 4835     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 4836     (write _test-input-stream "  x: int\n")
 4837     (write _test-input-stream "  y: int\n")
 4838     (write _test-input-stream "}\n")
 4839     (write _test-input-stream "fn foo {\n")
 4840     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4841     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4842     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4843     (write _test-input-stream "}\n")
 4844     # convert
 4845     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4846     (flush _test-output-buffered-file)
 4847 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4853     # check output
 4854     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 4855     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 4856     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 4857     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 4858     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 4859     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 4860     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 4861     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 4862     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 4863     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 4864     (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")
 4865     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 4866     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 4867     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 4868     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 4869     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 4870     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 4871     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 4872     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 4873     # . epilogue
 4874     89/<- %esp 5/r32/ebp
 4875     5d/pop-to-ebp
 4876     c3/return
 4877 
 4878 test-convert-length-of-array-of-user-defined-types-to-eax:
 4879     # . prologue
 4880     55/push-ebp
 4881     89/<- %ebp 4/r32/esp
 4882     # setup
 4883     (clear-stream _test-input-stream)
 4884     (clear-stream $_test-input-buffered-file->buffer)
 4885     (clear-stream _test-output-stream)
 4886     (clear-stream $_test-output-buffered-file->buffer)
 4887     #
 4888     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 4889     (write _test-input-stream "  x: int\n")
 4890     (write _test-input-stream "  y: int\n")
 4891     (write _test-input-stream "  z: int\n")
 4892     (write _test-input-stream "}\n")
 4893     (write _test-input-stream "fn foo {\n")
 4894     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4895     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 4896     (write _test-input-stream "}\n")
 4897     # convert
 4898     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4899     (flush _test-output-buffered-file)
 4900 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4906     # check output
 4907     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 4908     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 4909     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 4910     (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")
 4911     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 4912     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 4913     # var arr
 4914     (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")
 4915     (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")
 4916     # length instruction
 4917     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 4918     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 4919     (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")
 4920     (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")
 4921     (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")
 4922     (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")
 4923     (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")
 4924     (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")
 4925     # reclaim arr
 4926     (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")
 4927     #
 4928     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 4929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 4930     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 4931     (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")
 4932     (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")
 4933     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 4934     # . epilogue
 4935     89/<- %esp 5/r32/ebp
 4936     5d/pop-to-ebp
 4937     c3/return
 4938 
 4939 test-convert-length-of-array-of-user-defined-types-to-ecx:
 4940     # . prologue
 4941     55/push-ebp
 4942     89/<- %ebp 4/r32/esp
 4943     # setup
 4944     (clear-stream _test-input-stream)
 4945     (clear-stream $_test-input-buffered-file->buffer)
 4946     (clear-stream _test-output-stream)
 4947     (clear-stream $_test-output-buffered-file->buffer)
 4948     #
 4949     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 4950     (write _test-input-stream "  x: int\n")
 4951     (write _test-input-stream "  y: int\n")
 4952     (write _test-input-stream "  z: int\n")
 4953     (write _test-input-stream "}\n")
 4954     (write _test-input-stream "fn foo {\n")
 4955     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4956     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 4957     (write _test-input-stream "}\n")
 4958     # convert
 4959     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4960     (flush _test-output-buffered-file)
 4961 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4967     # check output
 4968     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 4969     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 4970     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 4971     (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")
 4972     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 4973     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 4974     # var a
 4975     (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")
 4976     (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")
 4977     # var x
 4978     (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")
 4979     # length instruction
 4980     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 4981     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 4982     (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")
 4983     (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")
 4984     (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")
 4985     (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")
 4986     (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")
 4987     (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")
 4988     (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")
 4989     # reclaim x
 4990     (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")
 4991     # reclaim a
 4992     (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")
 4993     #
 4994     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 4995     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 4996     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 4997     (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")
 4998     (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")
 4999     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 5000     # . epilogue
 5001     89/<- %esp 5/r32/ebp
 5002     5d/pop-to-ebp
 5003     c3/return
 5004 
 5005 test-convert-length-of-array-of-user-defined-types-to-edx:
 5006     # . prologue
 5007     55/push-ebp
 5008     89/<- %ebp 4/r32/esp
 5009     # setup
 5010     (clear-stream _test-input-stream)
 5011     (clear-stream $_test-input-buffered-file->buffer)
 5012     (clear-stream _test-output-stream)
 5013     (clear-stream $_test-output-buffered-file->buffer)
 5014     #
 5015     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5016     (write _test-input-stream "  x: int\n")
 5017     (write _test-input-stream "  y: int\n")
 5018     (write _test-input-stream "  z: int\n")
 5019     (write _test-input-stream "}\n")
 5020     (write _test-input-stream "fn foo {\n")
 5021     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5022     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 5023     (write _test-input-stream "}\n")
 5024     # convert
 5025     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5026     (flush _test-output-buffered-file)
 5027 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5033     # check output
 5034     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 5035     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 5036     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 5037     (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")
 5038     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 5039     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 5040     # var a
 5041     (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")
 5042     (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")
 5043     # var x
 5044     (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")
 5045     # length instruction
 5046     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 5047     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 5048     (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")
 5049     (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")
 5050     (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")
 5051     (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")
 5052     (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")
 5053     (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")
 5054     (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")
 5055     # reclaim x
 5056     (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")
 5057     # reclaim a
 5058     (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")
 5059     #
 5060     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 5061     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 5062     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 5063     (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")
 5064     (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")
 5065     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 5066     # . epilogue
 5067     89/<- %esp 5/r32/ebp
 5068     5d/pop-to-ebp
 5069     c3/return
 5070 
 5071 test-convert-length-of-array-of-user-defined-types:
 5072     # . prologue
 5073     55/push-ebp
 5074     89/<- %ebp 4/r32/esp
 5075     # setup
 5076     (clear-stream _test-input-stream)
 5077     (clear-stream $_test-input-buffered-file->buffer)
 5078     (clear-stream _test-output-stream)
 5079     (clear-stream $_test-output-buffered-file->buffer)
 5080     #
 5081     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 5082     (write _test-input-stream "  x: int\n")
 5083     (write _test-input-stream "  y: int\n")
 5084     (write _test-input-stream "  z: int\n")
 5085     (write _test-input-stream "}\n")
 5086     (write _test-input-stream "fn foo {\n")
 5087     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5088     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 5089     (write _test-input-stream "}\n")
 5090     # convert
 5091     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5092     (flush _test-output-buffered-file)
 5093 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5099     # check output
 5100     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 5101     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 5102     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 5103     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 5104     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 5105     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 5106     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 5107     (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")
 5108     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 5109     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 5110     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 5111     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 5112     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 5113     (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")
 5114     (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")
 5115     (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")
 5116     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 5117     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 5118     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 5119     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 5120     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 5121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 5122     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 5123     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 5124     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 5125     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 5126     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 5127     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 5128     # . epilogue
 5129     89/<- %esp 5/r32/ebp
 5130     5d/pop-to-ebp
 5131     c3/return
 5132 
 5133 #######################################################
 5134 # Parsing
 5135 #######################################################
 5136 
 5137 == data
 5138 
 5139 # Global state added to each var record when parsing a function
 5140 Next-block-index:  # (addr int)
 5141     1/imm32
 5142 
 5143 Curr-block-depth:  # (addr int)
 5144     1/imm32
 5145 
 5146 == code
 5147 
 5148 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 5149     # pseudocode
 5150     #   var curr-function: (addr handle function) = Program->functions
 5151     #   var curr-type: (addr handle typeinfo) = Program->types
 5152     #   var line: (stream byte 512)
 5153     #   var word-slice: slice
 5154     #   while true                                  # line loop
 5155     #     clear-stream(line)
 5156     #     read-line-buffered(in, line)
 5157     #     if (line->write == 0) break               # end of file
 5158     #     word-slice = next-mu-token(line)
 5159     #     if slice-empty?(word-slice)               # end of line
 5160     #       continue
 5161     #     else if slice-starts-with?(word-slice, "#")  # comment
 5162     #       continue                                # end of line
 5163     #     else if slice-equal?(word-slice, "fn")
 5164     #       var new-function: (handle function) = allocate(function)
 5165     #       var vars: (stack live-var 256)
 5166     #       populate-mu-function-header(line, new-function, vars)
 5167     #       populate-mu-function-body(in, new-function, vars)
 5168     #       assert(vars->top == 0)
 5169     #       *curr-function = new-function
 5170     #       curr-function = &new-function->next
 5171     #     else if slice-equal?(word-slice, "type")
 5172     #       word-slice = next-mu-token(line)
 5173     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 5174     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 5175     #       assert(next-word(line) == "{")
 5176     #       populate-mu-type(in, new-type)
 5177     #     else
 5178     #       abort()
 5179     #
 5180     # . prologue
 5181     55/push-ebp
 5182     89/<- %ebp 4/r32/esp
 5183     # . save registers
 5184     50/push-eax
 5185     51/push-ecx
 5186     52/push-edx
 5187     53/push-ebx
 5188     56/push-esi
 5189     57/push-edi
 5190     # var line/ecx: (stream byte 512)
 5191     81 5/subop/subtract %esp 0x200/imm32
 5192     68/push 0x200/imm32/size
 5193     68/push 0/imm32/read
 5194     68/push 0/imm32/write
 5195     89/<- %ecx 4/r32/esp
 5196     # var word-slice/edx: slice
 5197     68/push 0/imm32/end
 5198     68/push 0/imm32/start
 5199     89/<- %edx 4/r32/esp
 5200     # var curr-function/edi: (addr handle function)
 5201     bf/copy-to-edi _Program-functions/imm32
 5202     # var vars/ebx: (stack live-var 256)
 5203     81 5/subop/subtract %esp 0xc00/imm32
 5204     68/push 0xc00/imm32/size
 5205     68/push 0/imm32/top
 5206     89/<- %ebx 4/r32/esp
 5207     {
 5208 $parse-mu:line-loop:
 5209       (clear-stream %ecx)
 5210       (read-line-buffered *(ebp+8) %ecx)
 5211       # if (line->write == 0) break
 5212       81 7/subop/compare *ecx 0/imm32
 5213       0f 84/jump-if-= break/disp32
 5214 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 5220       (next-mu-token %ecx %edx)
 5221       # if slice-empty?(word-slice) continue
 5222       (slice-empty? %edx)  # => eax
 5223       3d/compare-eax-and 0/imm32/false
 5224       0f 85/jump-if-!= loop/disp32
 5225       # if (*word-slice->start == "#") continue
 5226       # . eax = *word-slice->start
 5227       8b/-> *edx 0/r32/eax
 5228       8a/copy-byte *eax 0/r32/AL
 5229       81 4/subop/and %eax 0xff/imm32
 5230       # . if (eax == '#') continue
 5231       3d/compare-eax-and 0x23/imm32/hash
 5232       0f 84/jump-if-= loop/disp32
 5233       # if (slice-equal?(word-slice, "fn")) parse a function
 5234       {
 5235 $parse-mu:fn:
 5236         (slice-equal? %edx "fn")  # => eax
 5237         3d/compare-eax-and 0/imm32/false
 5238         0f 84/jump-if-= break/disp32
 5239         # var new-function/esi: (handle function)
 5240         68/push 0/imm32
 5241         68/push 0/imm32
 5242         89/<- %esi 4/r32/esp
 5243         # populate-mu-function(line, in, vars, new-function)
 5244         (allocate Heap *Function-size %esi)
 5245         # var new-function-addr/eax: (addr function)
 5246         (lookup *esi *(esi+4))  # => eax
 5247         (clear-stack %ebx)
 5248         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 5249         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 5250         # *curr-function = new-function
 5251         8b/-> *esi 0/r32/eax
 5252         89/<- *edi 0/r32/eax
 5253         8b/-> *(esi+4) 0/r32/eax
 5254         89/<- *(edi+4) 0/r32/eax
 5255         # curr-function = &new-function->next
 5256         # . var tmp/eax: (addr function) = lookup(new-function)
 5257         (lookup *esi *(esi+4))  # => eax
 5258         # . curr-function = &tmp->next
 5259         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 5260         # reclaim new-function
 5261         81 0/subop/add %esp 8/imm32
 5262         #
 5263         e9/jump $parse-mu:line-loop/disp32
 5264       }
 5265       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 5266       {
 5267 $parse-mu:type:
 5268         (slice-equal? %edx "type")  # => eax
 5269         3d/compare-eax-and 0/imm32
 5270         0f 84/jump-if-= break/disp32
 5271         (next-mu-token %ecx %edx)
 5272         # var type-id/eax: int
 5273         (pos-or-insert-slice Type-id %edx)  # => eax
 5274         # spill
 5275         51/push-ecx
 5276         # var new-type/ecx: (handle typeinfo)
 5277         68/push 0/imm32
 5278         68/push 0/imm32
 5279         89/<- %ecx 4/r32/esp
 5280         (find-or-create-typeinfo %eax %ecx)
 5281         #
 5282         (lookup *ecx *(ecx+4))  # => eax
 5283         # TODO: ensure that 'line' has nothing else but '{'
 5284 #? (dump-typeinfos "=== aaa\n")
 5285         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 5286 #? (dump-typeinfos "=== zzz\n")
 5287         # reclaim new-type
 5288         81 0/subop/add %esp 8/imm32
 5289         # restore
 5290         59/pop-to-ecx
 5291         e9/jump $parse-mu:line-loop/disp32
 5292       }
 5293       # otherwise abort
 5294       e9/jump $parse-mu:error1/disp32
 5295     } # end line loop
 5296 $parse-mu:end:
 5297     # . reclaim locals
 5298     81 0/subop/add %esp 0xe1c/imm32
 5299     # . restore registers
 5300     5f/pop-to-edi
 5301     5e/pop-to-esi
 5302     5b/pop-to-ebx
 5303     5a/pop-to-edx
 5304     59/pop-to-ecx
 5305     58/pop-to-eax
 5306     # . epilogue
 5307     89/<- %esp 5/r32/ebp
 5308     5d/pop-to-ebp
 5309     c3/return
 5310 
 5311 $parse-mu:error1:
 5312     # error("unexpected top-level command: " word-slice "\n")
 5313     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 5314     (write-slice-buffered *(ebp+0xc) %edx)
 5315     (write-buffered *(ebp+0xc) "\n")
 5316     (flush *(ebp+0xc))
 5317     (stop *(ebp+0x10) 1)
 5318     # never gets here
 5319 
 5320 $parse-mu:error2:
 5321     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 5322     (print-int32-buffered *(ebp+0xc) *ebx)
 5323     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 5324     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 5325     (write-buffered *(ebp+0xc) "'\n")
 5326     (flush *(ebp+0xc))
 5327     (stop *(ebp+0x10) 1)
 5328     # never gets here
 5329 
 5330 # scenarios considered:
 5331 # ✗ fn foo  # no block
 5332 # ✓ fn foo {
 5333 # ✗ fn foo { {
 5334 # ✗ fn foo { }
 5335 # ✗ fn foo { } {
 5336 # ✗ fn foo x {
 5337 # ✗ fn foo x: {
 5338 # ✓ fn foo x: int {
 5339 # ✓ fn foo x: int {
 5340 # ✓ fn foo x: int -> y/eax: int {
 5341 # TODO:
 5342 #   disallow outputs of type `(... addr ...)`
 5343 #   disallow inputs of type `(... addr ... addr ...)`
 5344 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)
 5345     # pseudocode:
 5346     #   var name: slice
 5347     #   next-mu-token(first-line, name)
 5348     #   assert(name not in '{' '}' '->')
 5349     #   out->name = slice-to-string(name)
 5350     #   ## inouts
 5351     #   while true
 5352     #     ## name
 5353     #     name = next-mu-token(first-line)
 5354     #     if (name == '{') goto done
 5355     #     if (name == '->') break
 5356     #     assert(name != '}')
 5357     #     var v: (handle var) = parse-var-with-type(name, first-line)
 5358     #     assert(v->register == null)
 5359     #     # v->block-depth is implicitly 0
 5360     #     out->inouts = append(v, out->inouts)
 5361     #     push(vars, {v, false})
 5362     #   ## outputs
 5363     #   while true
 5364     #     ## name
 5365     #     name = next-mu-token(first-line)
 5366     #     assert(name not in '{' '}' '->')
 5367     #     var v: (handle var) = parse-var-with-type(name, first-line)
 5368     #     assert(v->register != null)
 5369     #     out->outputs = append(v, out->outputs)
 5370     #   done:
 5371     #
 5372     # . prologue
 5373     55/push-ebp
 5374     89/<- %ebp 4/r32/esp
 5375     # . save registers
 5376     50/push-eax
 5377     51/push-ecx
 5378     52/push-edx
 5379     53/push-ebx
 5380     57/push-edi
 5381     # edi = out
 5382     8b/-> *(ebp+0xc) 7/r32/edi
 5383     # var word-slice/ecx: slice
 5384     68/push 0/imm32/end
 5385     68/push 0/imm32/start
 5386     89/<- %ecx 4/r32/esp
 5387     # var v/ebx: (handle var)
 5388     68/push 0/imm32
 5389     68/push 0/imm32
 5390     89/<- %ebx 4/r32/esp
 5391     # read function name
 5392     (next-mu-token *(ebp+8) %ecx)
 5393     # error checking
 5394     # TODO: error if name starts with 'break' or 'loop'
 5395     # if (word-slice == '{') abort
 5396     (slice-equal? %ecx "{")   # => eax
 5397     3d/compare-eax-and 0/imm32/false
 5398     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5399     # if (word-slice == '->') abort
 5400     (slice-equal? %ecx "->")   # => eax
 5401     3d/compare-eax-and 0/imm32/false
 5402     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5403     # if (word-slice == '}') abort
 5404     (slice-equal? %ecx "}")   # => eax
 5405     3d/compare-eax-and 0/imm32/false
 5406     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5407     # save function name
 5408     (slice-to-string Heap %ecx %edi)  # Function-name
 5409     # save function inouts
 5410     {
 5411 $populate-mu-function-header:check-for-inout:
 5412       (next-mu-token *(ebp+8) %ecx)
 5413       # if (word-slice == '{') goto done
 5414       (slice-equal? %ecx "{")   # => eax
 5415       3d/compare-eax-and 0/imm32/false
 5416       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 5417       # if (word-slice == '->') break
 5418       (slice-equal? %ecx "->")   # => eax
 5419       3d/compare-eax-and 0/imm32/false
 5420       0f 85/jump-if-!= break/disp32
 5421       # if (word-slice == '}') abort
 5422       (slice-equal? %ecx "}")   # => eax
 5423       3d/compare-eax-and 0/imm32/false
 5424       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5425       # v = parse-var-with-type(word-slice, first-line)
 5426       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 5427       # assert(v->register == null)
 5428       # . eax: (addr var) = lookup(v)
 5429       (lookup *ebx *(ebx+4))  # => eax
 5430       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 5431       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 5432       # v->block-depth is implicitly 0
 5433       #
 5434       # out->inouts = append(v, out->inouts)
 5435       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 5436       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 5437       # push(vars, {v, false})
 5438       (push *(ebp+0x10) *ebx)
 5439       (push *(ebp+0x10) *(ebx+4))
 5440       (push *(ebp+0x10) 0)  # false
 5441       #
 5442       e9/jump loop/disp32
 5443     }
 5444     # save function outputs
 5445     {
 5446 $populate-mu-function-header:check-for-out:
 5447       (next-mu-token *(ebp+8) %ecx)
 5448       # if (word-slice == '{') break
 5449       (slice-equal? %ecx "{")   # => eax
 5450       3d/compare-eax-and 0/imm32/false
 5451       0f 85/jump-if-!= break/disp32
 5452       # if (word-slice == '->') abort
 5453       (slice-equal? %ecx "->")   # => eax
 5454       3d/compare-eax-and 0/imm32/false
 5455       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5456       # if (word-slice == '}') abort
 5457       (slice-equal? %ecx "}")   # => eax
 5458       3d/compare-eax-and 0/imm32/false
 5459       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5460       # v = parse-var-with-type(word-slice, first-line)
 5461       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 5462       # assert(var->register != null)
 5463       # . eax: (addr var) = lookup(v)
 5464       (lookup *ebx *(ebx+4))  # => eax
 5465       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 5466       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 5467       # out->outputs = append(v, out->outputs)
 5468       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 5469       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 5470       #
 5471       e9/jump loop/disp32
 5472     }
 5473 $populate-mu-function-header:done:
 5474     (check-no-tokens-left *(ebp+8))
 5475 $populate-mu-function-header:end:
 5476     # . reclaim locals
 5477     81 0/subop/add %esp 0x10/imm32
 5478     # . restore registers
 5479     5f/pop-to-edi
 5480     5b/pop-to-ebx
 5481     5a/pop-to-edx
 5482     59/pop-to-ecx
 5483     58/pop-to-eax
 5484     # . epilogue
 5485     89/<- %esp 5/r32/ebp
 5486     5d/pop-to-ebp
 5487     c3/return
 5488 
 5489 $populate-mu-function-header:error1:
 5490     # error("function header not in form 'fn <name> {'")
 5491     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 5492     (flush *(ebp+0x14))
 5493     (rewind-stream *(ebp+8))
 5494     (write-stream-data *(ebp+0x14) *(ebp+8))
 5495     (write-buffered *(ebp+0x14) "'\n")
 5496     (flush *(ebp+0x14))
 5497     (stop *(ebp+0x18) 1)
 5498     # never gets here
 5499 
 5500 $populate-mu-function-header:error2:
 5501     # error("function inout '" var "' cannot be in a register")
 5502     (write-buffered *(ebp+0x14) "function inout '")
 5503     (write-buffered *(ebp+0x14) *ebx)  # Var-name
 5504     (write-buffered *(ebp+0x14) "' cannot be in a register")
 5505     (flush *(ebp+0x14))
 5506     (stop *(ebp+0x18) 1)
 5507     # never gets here
 5508 
 5509 $populate-mu-function-header:error3:
 5510     # error("function output '" var "' must be in a register")
 5511     (write-buffered *(ebp+0x14) "function output '")
 5512     (lookup *ebx *(ebx+4))  # => eax
 5513     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 5514     (write-buffered *(ebp+0x14) %eax)
 5515     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 5516     (rewind-stream *(ebp+8))
 5517     (write-stream-data *(ebp+0x14) *(ebp+8))
 5518     (write-buffered *(ebp+0x14) "'\n")
 5519     (flush *(ebp+0x14))
 5520     (stop *(ebp+0x18) 1)
 5521     # never gets here
 5522 
 5523 test-function-header-with-arg:
 5524     # . prologue
 5525     55/push-ebp
 5526     89/<- %ebp 4/r32/esp
 5527     # setup
 5528     (clear-stream _test-input-stream)
 5529     (write _test-input-stream "foo n: int {\n")
 5530     # var result/ecx: function
 5531     2b/subtract *Function-size 4/r32/esp
 5532     89/<- %ecx 4/r32/esp
 5533     (zero-out %ecx *Function-size)
 5534     # var vars/ebx: (stack live-var 16)
 5535     81 5/subop/subtract %esp 0xc0/imm32
 5536     68/push 0xc0/imm32/size
 5537     68/push 0/imm32/top
 5538     89/<- %ebx 4/r32/esp
 5539     # convert
 5540     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5541     # check result->name
 5542     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5543     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 5544     # var v/edx: (addr var) = result->inouts->value
 5545     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5546     (lookup *eax *(eax+4))  # List-value List-value => eax
 5547     89/<- %edx 0/r32/eax
 5548     # check v->name
 5549     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5550     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 5551     # check v->type
 5552     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5553     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 5554     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 5555     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 5556     # . epilogue
 5557     89/<- %esp 5/r32/ebp
 5558     5d/pop-to-ebp
 5559     c3/return
 5560 
 5561 test-function-header-with-multiple-args:
 5562     # . prologue
 5563     55/push-ebp
 5564     89/<- %ebp 4/r32/esp
 5565     # setup
 5566     (clear-stream _test-input-stream)
 5567     (write _test-input-stream "foo a: int, b: int c: int {\n")
 5568     # result/ecx: function
 5569     2b/subtract *Function-size 4/r32/esp
 5570     89/<- %ecx 4/r32/esp
 5571     (zero-out %ecx *Function-size)
 5572     # var vars/ebx: (stack live-var 16)
 5573     81 5/subop/subtract %esp 0xc0/imm32
 5574     68/push 0xc0/imm32/size
 5575     68/push 0/imm32/top
 5576     89/<- %ebx 4/r32/esp
 5577     # convert
 5578     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5579     # check result->name
 5580     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5581     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 5582     # var inouts/edx: (addr list var) = lookup(result->inouts)
 5583     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5584     89/<- %edx 0/r32/eax
 5585 $test-function-header-with-multiple-args:inout0:
 5586     # var v/ebx: (addr var) = lookup(inouts->value)
 5587     (lookup *edx *(edx+4))  # List-value List-value => eax
 5588     89/<- %ebx 0/r32/eax
 5589     # check v->name
 5590     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5591     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 5592     # check v->type
 5593     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5594     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 5595     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 5596     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 5597 $test-function-header-with-multiple-args:inout1:
 5598     # inouts = lookup(inouts->next)
 5599     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5600     89/<- %edx 0/r32/eax
 5601     # v = lookup(inouts->value)
 5602     (lookup *edx *(edx+4))  # List-value List-value => eax
 5603     89/<- %ebx 0/r32/eax
 5604     # check v->name
 5605     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5606     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 5607     # check v->type
 5608     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5609     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 5610     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 5611     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 5612 $test-function-header-with-multiple-args:inout2:
 5613     # inouts = lookup(inouts->next)
 5614     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5615     89/<- %edx 0/r32/eax
 5616     # v = lookup(inouts->value)
 5617     (lookup *edx *(edx+4))  # List-value List-value => eax
 5618     89/<- %ebx 0/r32/eax
 5619     # check v->name
 5620     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5621     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 5622     # check v->type
 5623     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5624     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 5625     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 5626     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 5627     # . epilogue
 5628     89/<- %esp 5/r32/ebp
 5629     5d/pop-to-ebp
 5630     c3/return
 5631 
 5632 test-function-header-with-multiple-args-and-outputs:
 5633     # . prologue
 5634     55/push-ebp
 5635     89/<- %ebp 4/r32/esp
 5636     # setup
 5637     (clear-stream _test-input-stream)
 5638     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 5639     # result/ecx: function
 5640     2b/subtract *Function-size 4/r32/esp
 5641     89/<- %ecx 4/r32/esp
 5642     (zero-out %ecx *Function-size)
 5643     # var vars/ebx: (stack live-var 16)
 5644     81 5/subop/subtract %esp 0xc0/imm32
 5645     68/push 0xc0/imm32/size
 5646     68/push 0/imm32/top
 5647     89/<- %ebx 4/r32/esp
 5648     # convert
 5649     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5650     # check result->name
 5651     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5652     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 5653     # var inouts/edx: (addr list var) = lookup(result->inouts)
 5654     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5655     89/<- %edx 0/r32/eax
 5656 $test-function-header-with-multiple-args-and-outputs:inout0:
 5657     # var v/ebx: (addr var) = lookup(inouts->value)
 5658     (lookup *edx *(edx+4))  # List-value List-value => eax
 5659     89/<- %ebx 0/r32/eax
 5660     # check v->name
 5661     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5662     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 5663     # check v->type
 5664     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5665     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 5666     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 5667     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 5668 $test-function-header-with-multiple-args-and-outputs:inout1:
 5669     # inouts = lookup(inouts->next)
 5670     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5671     89/<- %edx 0/r32/eax
 5672     # v = lookup(inouts->value)
 5673     (lookup *edx *(edx+4))  # List-value List-value => eax
 5674     89/<- %ebx 0/r32/eax
 5675     # check v->name
 5676     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5677     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 5678     # check v->type
 5679     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5680     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 5681     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 5682     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 5683 $test-function-header-with-multiple-args-and-outputs:inout2:
 5684     # inouts = lookup(inouts->next)
 5685     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5686     89/<- %edx 0/r32/eax
 5687     # v = lookup(inouts->value)
 5688     (lookup *edx *(edx+4))  # List-value List-value => eax
 5689     89/<- %ebx 0/r32/eax
 5690     # check v->name
 5691     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5692     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 5693     # check v->type
 5694     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5695     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 5696     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 5697     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 5698 $test-function-header-with-multiple-args-and-outputs:out0:
 5699     # var outputs/edx: (addr list var) = lookup(result->outputs)
 5700     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 5701     89/<- %edx 0/r32/eax
 5702     # v = lookup(outputs->value)
 5703     (lookup *edx *(edx+4))  # List-value List-value => eax
 5704     89/<- %ebx 0/r32/eax
 5705     # check v->name
 5706     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5707     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 5708     # check v->register
 5709     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 5710     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 5711     # check v->type
 5712     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5713     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 5714     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 5715     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 5716 $test-function-header-with-multiple-args-and-outputs:out1:
 5717     # outputs = lookup(outputs->next)
 5718     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5719     89/<- %edx 0/r32/eax
 5720     # v = lookup(inouts->value)
 5721     (lookup *edx *(edx+4))  # List-value List-value => eax
 5722     89/<- %ebx 0/r32/eax
 5723     # check v->name
 5724     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5725     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 5726     # check v->register
 5727     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 5728     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 5729     # check v->type
 5730     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5731     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 5732     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 5733     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 5734     # . epilogue
 5735     89/<- %esp 5/r32/ebp
 5736     5d/pop-to-ebp
 5737     c3/return
 5738 
 5739 # format for variables with types
 5740 #   x: int
 5741 #   x: int,
 5742 #   x/eax: int
 5743 #   x/eax: int,
 5744 # ignores at most one trailing comma
 5745 # WARNING: modifies name
 5746 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 5747     # pseudocode:
 5748     #   var s: slice
 5749     #   if (!slice-ends-with(name, ":"))
 5750     #     abort
 5751     #   --name->end to skip ':'
 5752     #   next-token-from-slice(name->start, name->end, '/', s)
 5753     #   new-var-from-slice(s, out)
 5754     #   ## register
 5755     #   next-token-from-slice(s->end, name->end, '/', s)
 5756     #   if (!slice-empty?(s))
 5757     #     out->register = slice-to-string(s)
 5758     #   ## type
 5759     #   var type: (handle tree type-id) = parse-type(first-line)
 5760     #   out->type = type
 5761     #
 5762     # . prologue
 5763     55/push-ebp
 5764     89/<- %ebp 4/r32/esp
 5765     # . save registers
 5766     50/push-eax
 5767     51/push-ecx
 5768     52/push-edx
 5769     53/push-ebx
 5770     56/push-esi
 5771     57/push-edi
 5772     # esi = name
 5773     8b/-> *(ebp+8) 6/r32/esi
 5774     # if (!slice-ends-with?(name, ":")) abort
 5775     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 5776     49/decrement-ecx
 5777     8a/copy-byte *ecx 1/r32/CL
 5778     81 4/subop/and %ecx 0xff/imm32
 5779     81 7/subop/compare %ecx 0x3a/imm32/colon
 5780     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 5781     # --name->end to skip ':'
 5782     ff 1/subop/decrement *(esi+4)
 5783     # var s/ecx: slice
 5784     68/push 0/imm32/end
 5785     68/push 0/imm32/start
 5786     89/<- %ecx 4/r32/esp
 5787 $parse-var-with-type:parse-name:
 5788     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 5789 $parse-var-with-type:create-var:
 5790     # new-var-from-slice(s, out)
 5791     (new-var-from-slice Heap %ecx *(ebp+0x10))
 5792     # save out->register
 5793 $parse-var-with-type:save-register:
 5794     # . var out-addr/edi: (addr var) = lookup(*out)
 5795     8b/-> *(ebp+0x10) 7/r32/edi
 5796     (lookup *edi *(edi+4))  # => eax
 5797     89/<- %edi 0/r32/eax
 5798     # . s = next-token(...)
 5799     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 5800     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 5801     {
 5802 $parse-var-with-type:write-register:
 5803       (slice-empty? %ecx)  # => eax
 5804       3d/compare-eax-and 0/imm32/false
 5805       75/jump-if-!= break/disp8
 5806       # out->register = slice-to-string(s)
 5807       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 5808       (slice-to-string Heap %ecx %eax)
 5809     }
 5810 $parse-var-with-type:save-type:
 5811     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 5812     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5813 $parse-var-with-type:end:
 5814     # . reclaim locals
 5815     81 0/subop/add %esp 8/imm32
 5816     # . restore registers
 5817     5f/pop-to-edi
 5818     5e/pop-to-esi
 5819     5b/pop-to-ebx
 5820     5a/pop-to-edx
 5821     59/pop-to-ecx
 5822     58/pop-to-eax
 5823     # . epilogue
 5824     89/<- %esp 5/r32/ebp
 5825     5d/pop-to-ebp
 5826     c3/return
 5827 
 5828 $parse-var-with-type:abort:
 5829     # error("var should have form 'name: type' in '" line "'\n")
 5830     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 5831     (flush *(ebp+0x14))
 5832     (rewind-stream *(ebp+0xc))
 5833     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 5834     (write-buffered *(ebp+0x14) "'\n")
 5835     (flush *(ebp+0x14))
 5836     (stop *(ebp+0x18) 1)
 5837     # never gets here
 5838 
 5839 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 5840     # pseudocode:
 5841     #   var s: slice = next-mu-token(in)
 5842     #   assert s != ""
 5843     #   assert s != "->"
 5844     #   assert s != "{"
 5845     #   assert s != "}"
 5846     #   if s == ")"
 5847     #     return
 5848     #   out = allocate(Tree)
 5849     #   if s != "("
 5850     #     HACK: if s is an int, parse and return it
 5851     #     out->left-is-atom? = true
 5852     #     out->value = pos-or-insert-slice(Type-id, s)
 5853     #     return
 5854     #   out->left = parse-type(ad, in)
 5855     #   out->right = parse-type-tree(ad, in)
 5856     #
 5857     # . prologue
 5858     55/push-ebp
 5859     89/<- %ebp 4/r32/esp
 5860     # . save registers
 5861     50/push-eax
 5862     51/push-ecx
 5863     52/push-edx
 5864     # clear out
 5865     (zero-out *(ebp+0x10) *Handle-size)
 5866     # var s/ecx: slice
 5867     68/push 0/imm32
 5868     68/push 0/imm32
 5869     89/<- %ecx 4/r32/esp
 5870     # s = next-mu-token(in)
 5871     (next-mu-token *(ebp+0xc) %ecx)
 5872 #?     (write-buffered Stderr "tok: ")
 5873 #?     (write-slice-buffered Stderr %ecx)
 5874 #?     (write-buffered Stderr "$\n")
 5875 #?     (flush Stderr)
 5876     # assert s != ""
 5877     (slice-equal? %ecx "")  # => eax
 5878     3d/compare-eax-and 0/imm32/false
 5879     0f 85/jump-if-!= $parse-type:abort/disp32
 5880     # assert s != "{"
 5881     (slice-equal? %ecx "{")  # => eax
 5882     3d/compare-eax-and 0/imm32/false
 5883     0f 85/jump-if-!= $parse-type:abort/disp32
 5884     # assert s != "}"
 5885     (slice-equal? %ecx "}")  # => eax
 5886     3d/compare-eax-and 0/imm32/false
 5887     0f 85/jump-if-!= $parse-type:abort/disp32
 5888     # assert s != "->"
 5889     (slice-equal? %ecx "->")  # => eax
 5890     3d/compare-eax-and 0/imm32/false
 5891     0f 85/jump-if-!= $parse-type:abort/disp32
 5892     # if (s == ")") return
 5893     (slice-equal? %ecx ")")  # => eax
 5894     3d/compare-eax-and 0/imm32/false
 5895     0f 85/jump-if-!= $parse-type:end/disp32
 5896     # out = new tree
 5897     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 5898     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 5899     8b/-> *(ebp+0x10) 2/r32/edx
 5900     (lookup *edx *(edx+4))  # => eax
 5901     89/<- %edx 0/r32/eax
 5902     {
 5903       # if (s != "(") break
 5904       (slice-equal? %ecx "(")  # => eax
 5905       3d/compare-eax-and 0/imm32/false
 5906       75/jump-if-!= break/disp8
 5907       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 5908       {
 5909 $parse-type:check-for-int:
 5910         (is-hex-int? %ecx)  # => eax
 5911         3d/compare-eax-and 0/imm32/false
 5912         74/jump-if-= break/disp8
 5913 $parse-type:int:
 5914         (parse-hex-int-from-slice %ecx)  # => eax
 5915         89/<- *(edx+4) 0/r32/eax  # Tree-value
 5916         e9/jump $parse-type:end/disp32
 5917       }
 5918 $parse-type:atom:
 5919       # out->left-is-atom? = true
 5920       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 5921       # out->value = pos-or-insert-slice(Type-id, s)
 5922       (pos-or-insert-slice Type-id %ecx)  # => eax
 5923       89/<- *(edx+4) 0/r32/eax  # Tree-value
 5924       e9/jump $parse-type:end/disp32
 5925     }
 5926 $parse-type:non-atom:
 5927     # otherwise s == "("
 5928     # out->left = parse-type(ad, in)
 5929     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 5930     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5931     # out->right = parse-type-tree(ad, in)
 5932     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 5933     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5934 $parse-type:end:
 5935     # . reclaim locals
 5936     81 0/subop/add %esp 8/imm32
 5937     # . restore registers
 5938     5a/pop-to-edx
 5939     59/pop-to-ecx
 5940     58/pop-to-eax
 5941     # . epilogue
 5942     89/<- %esp 5/r32/ebp
 5943     5d/pop-to-ebp
 5944     c3/return
 5945 
 5946 $parse-type:abort:
 5947     # error("unexpected token when parsing type: '" s "'\n")
 5948     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 5949     (write-slice-buffered *(ebp+0x14) %ecx)
 5950     (write-buffered *(ebp+0x14) "'\n")
 5951     (flush *(ebp+0x14))
 5952     (stop *(ebp+0x18) 1)
 5953     # never gets here
 5954 
 5955 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 5956     # pseudocode:
 5957     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 5958     #   if tmp == 0
 5959     #     return 0
 5960     #   out = allocate(Tree)
 5961     #   out->left = tmp
 5962     #   out->right = parse-type-tree(ad, in)
 5963     #
 5964     # . prologue
 5965     55/push-ebp
 5966     89/<- %ebp 4/r32/esp
 5967     # . save registers
 5968     50/push-eax
 5969     51/push-ecx
 5970     52/push-edx
 5971     #
 5972     (zero-out *(ebp+0x10) *Handle-size)
 5973     # var tmp/ecx: (handle tree type-id)
 5974     68/push 0/imm32
 5975     68/push 0/imm32
 5976     89/<- %ecx 4/r32/esp
 5977     # tmp = parse-type(ad, in)
 5978     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 5979     # if (tmp == 0) return
 5980     81 7/subop/compare *ecx 0/imm32
 5981     74/jump-if-= $parse-type-tree:end/disp8
 5982     # out = new tree
 5983     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 5984     # var out-addr/edx: (addr tree) = lookup(*out)
 5985     8b/-> *(ebp+0x10) 2/r32/edx
 5986     (lookup *edx *(edx+4))  # => eax
 5987     89/<- %edx 0/r32/eax
 5988     # out->left = tmp
 5989     8b/-> *ecx 0/r32/eax
 5990     89/<- *(edx+4) 0/r32/eax  # Tree-left
 5991     8b/-> *(ecx+4) 0/r32/eax
 5992     89/<- *(edx+8) 0/r32/eax  # Tree-left
 5993     # out->right = parse-type-tree(ad, in)
 5994     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 5995     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5996 $parse-type-tree:end:
 5997     # . reclaim locals
 5998     81 0/subop/add %esp 8/imm32
 5999     # . restore registers
 6000     5a/pop-to-edx
 6001     59/pop-to-ecx
 6002     58/pop-to-eax
 6003     # . epilogue
 6004     89/<- %esp 5/r32/ebp
 6005     5d/pop-to-ebp
 6006     c3/return
 6007 
 6008 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 6009     # pseudocode:
 6010     # start:
 6011     #   skip-chars-matching-whitespace(in)
 6012     #   if in->read >= in->write              # end of in
 6013     #     out = {0, 0}
 6014     #     return
 6015     #   out->start = &in->data[in->read]
 6016     #   var curr-byte/eax: byte = in->data[in->read]
 6017     #   if curr->byte == ','                  # comment token
 6018     #     ++in->read
 6019     #     goto start
 6020     #   if curr-byte == '#'                   # comment
 6021     #     goto done                             # treat as eof
 6022     #   if curr-byte == '"'                   # string literal
 6023     #     skip-string(in)
 6024     #     goto done                           # no metadata
 6025     #   if curr-byte == '('
 6026     #     ++in->read
 6027     #     goto done
 6028     #   if curr-byte == ')'
 6029     #     ++in->read
 6030     #     goto done
 6031     #   # read a word
 6032     #   while true
 6033     #     if in->read >= in->write
 6034     #       break
 6035     #     curr-byte = in->data[in->read]
 6036     #     if curr-byte == ' '
 6037     #       break
 6038     #     if curr-byte == '\r'
 6039     #       break
 6040     #     if curr-byte == '\n'
 6041     #       break
 6042     #     if curr-byte == '('
 6043     #       break
 6044     #     if curr-byte == ')'
 6045     #       break
 6046     #     if curr-byte == ','
 6047     #       break
 6048     #     ++in->read
 6049     # done:
 6050     #   out->end = &in->data[in->read]
 6051     #
 6052     # . prologue
 6053     55/push-ebp
 6054     89/<- %ebp 4/r32/esp
 6055     # . save registers
 6056     50/push-eax
 6057     51/push-ecx
 6058     56/push-esi
 6059     57/push-edi
 6060     # esi = in
 6061     8b/-> *(ebp+8) 6/r32/esi
 6062     # edi = out
 6063     8b/-> *(ebp+0xc) 7/r32/edi
 6064 $next-mu-token:start:
 6065     (skip-chars-matching-whitespace %esi)
 6066 $next-mu-token:check0:
 6067     # if (in->read >= in->write) return out = {0, 0}
 6068     # . ecx = in->read
 6069     8b/-> *(esi+4) 1/r32/ecx
 6070     # . if (ecx >= in->write) return out = {0, 0}
 6071     3b/compare<- *esi 1/r32/ecx
 6072     c7 0/subop/copy *edi 0/imm32
 6073     c7 0/subop/copy *(edi+4) 0/imm32
 6074     0f 8d/jump-if->= $next-mu-token:end/disp32
 6075     # out->start = &in->data[in->read]
 6076     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 6077     89/<- *edi 0/r32/eax
 6078     # var curr-byte/eax: byte = in->data[in->read]
 6079     31/xor-with %eax 0/r32/eax
 6080     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 6081     {
 6082 $next-mu-token:check-for-comma:
 6083       # if (curr-byte != ',') break
 6084       3d/compare-eax-and 0x2c/imm32/comma
 6085       75/jump-if-!= break/disp8
 6086       # ++in->read
 6087       ff 0/subop/increment *(esi+4)
 6088       # restart
 6089       e9/jump $next-mu-token:start/disp32
 6090     }
 6091     {
 6092 $next-mu-token:check-for-comment:
 6093       # if (curr-byte != '#') break
 6094       3d/compare-eax-and 0x23/imm32/pound
 6095       75/jump-if-!= break/disp8
 6096       # return eof
 6097       e9/jump $next-mu-token:done/disp32
 6098     }
 6099     {
 6100 $next-mu-token:check-for-string-literal:
 6101       # if (curr-byte != '"') break
 6102       3d/compare-eax-and 0x22/imm32/dquote
 6103       75/jump-if-!= break/disp8
 6104       (skip-string %esi)
 6105       # return
 6106       e9/jump $next-mu-token:done/disp32
 6107     }
 6108     {
 6109 $next-mu-token:check-for-open-paren:
 6110       # if (curr-byte != '(') break
 6111       3d/compare-eax-and 0x28/imm32/open-paren
 6112       75/jump-if-!= break/disp8
 6113       # ++in->read
 6114       ff 0/subop/increment *(esi+4)
 6115       # return
 6116       e9/jump $next-mu-token:done/disp32
 6117     }
 6118     {
 6119 $next-mu-token:check-for-close-paren:
 6120       # if (curr-byte != ')') break
 6121       3d/compare-eax-and 0x29/imm32/close-paren
 6122       75/jump-if-!= break/disp8
 6123       # ++in->read
 6124       ff 0/subop/increment *(esi+4)
 6125       # return
 6126       e9/jump $next-mu-token:done/disp32
 6127     }
 6128     {
 6129 $next-mu-token:regular-word-without-metadata:
 6130       # if (in->read >= in->write) break
 6131       # . ecx = in->read
 6132       8b/-> *(esi+4) 1/r32/ecx
 6133       # . if (ecx >= in->write) break
 6134       3b/compare<- *esi 1/r32/ecx
 6135       7d/jump-if->= break/disp8
 6136       # var c/eax: byte = in->data[in->read]
 6137       31/xor-with %eax 0/r32/eax
 6138       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 6139       # if (c == ' ') break
 6140       3d/compare-eax-and 0x20/imm32/space
 6141       74/jump-if-= break/disp8
 6142       # if (c == '\r') break
 6143       3d/compare-eax-and 0xd/imm32/carriage-return
 6144       74/jump-if-= break/disp8
 6145       # if (c == '\n') break
 6146       3d/compare-eax-and 0xa/imm32/newline
 6147       74/jump-if-= break/disp8
 6148       # if (c == '(') break
 6149       3d/compare-eax-and 0x28/imm32/open-paren
 6150       0f 84/jump-if-= break/disp32
 6151       # if (c == ')') break
 6152       3d/compare-eax-and 0x29/imm32/close-paren
 6153       0f 84/jump-if-= break/disp32
 6154       # if (c == ',') break
 6155       3d/compare-eax-and 0x2c/imm32/comma
 6156       0f 84/jump-if-= break/disp32
 6157       # ++in->read
 6158       ff 0/subop/increment *(esi+4)
 6159       #
 6160       e9/jump loop/disp32
 6161     }
 6162 $next-mu-token:done:
 6163     # out->end = &in->data[in->read]
 6164     8b/-> *(esi+4) 1/r32/ecx
 6165     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 6166     89/<- *(edi+4) 0/r32/eax
 6167 $next-mu-token:end:
 6168     # . restore registers
 6169     5f/pop-to-edi
 6170     5e/pop-to-esi
 6171     59/pop-to-ecx
 6172     58/pop-to-eax
 6173     # . epilogue
 6174     89/<- %esp 5/r32/ebp
 6175     5d/pop-to-ebp
 6176     c3/return
 6177 
 6178 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 6179     # . prologue
 6180     55/push-ebp
 6181     89/<- %ebp 4/r32/esp
 6182     # if (pos-slice(arr, s) != -1) return it
 6183     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 6184     3d/compare-eax-and -1/imm32
 6185     75/jump-if-!= $pos-or-insert-slice:end/disp8
 6186 $pos-or-insert-slice:insert:
 6187     # var s2/eax: (handle array byte)
 6188     68/push 0/imm32
 6189     68/push 0/imm32
 6190     89/<- %eax 4/r32/esp
 6191     (slice-to-string Heap *(ebp+0xc) %eax)
 6192     # throw away alloc-id
 6193     (lookup *eax *(eax+4))  # => eax
 6194     (write-int *(ebp+8) %eax)
 6195     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 6196 $pos-or-insert-slice:end:
 6197     # . reclaim locals
 6198     81 0/subop/add %esp 8/imm32
 6199     # . epilogue
 6200     89/<- %esp 5/r32/ebp
 6201     5d/pop-to-ebp
 6202     c3/return
 6203 
 6204 # return the index in an array of strings matching 's', -1 if not found
 6205 # index is denominated in elements, not bytes
 6206 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 6207     # . prologue
 6208     55/push-ebp
 6209     89/<- %ebp 4/r32/esp
 6210     # . save registers
 6211     51/push-ecx
 6212     52/push-edx
 6213     53/push-ebx
 6214     56/push-esi
 6215 #?     (write-buffered Stderr "pos-slice: ")
 6216 #?     (write-slice-buffered Stderr *(ebp+0xc))
 6217 #?     (write-buffered Stderr "\n")
 6218 #?     (flush Stderr)
 6219     # esi = arr
 6220     8b/-> *(ebp+8) 6/r32/esi
 6221     # var index/ecx: int = 0
 6222     b9/copy-to-ecx 0/imm32
 6223     # var curr/edx: (addr (addr array byte)) = arr->data
 6224     8d/copy-address *(esi+0xc) 2/r32/edx
 6225     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 6226     8b/-> *esi 3/r32/ebx
 6227     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 6228     {
 6229 #?       (write-buffered Stderr "  ")
 6230 #?       (print-int32-buffered Stderr %ecx)
 6231 #?       (write-buffered Stderr "\n")
 6232 #?       (flush Stderr)
 6233       # if (curr >= max) return -1
 6234       39/compare %edx 3/r32/ebx
 6235       b8/copy-to-eax -1/imm32
 6236       73/jump-if-addr>= $pos-slice:end/disp8
 6237       # if (slice-equal?(s, *curr)) break
 6238       (slice-equal? *(ebp+0xc) *edx)  # => eax
 6239       3d/compare-eax-and 0/imm32/false
 6240       75/jump-if-!= break/disp8
 6241       # ++index
 6242       41/increment-ecx
 6243       # curr += 4
 6244       81 0/subop/add %edx 4/imm32
 6245       #
 6246       eb/jump loop/disp8
 6247     }
 6248     # return index
 6249     89/<- %eax 1/r32/ecx
 6250 $pos-slice:end:
 6251 #?     (write-buffered Stderr "=> ")
 6252 #?     (print-int32-buffered Stderr %eax)
 6253 #?     (write-buffered Stderr "\n")
 6254     # . restore registers
 6255     5e/pop-to-esi
 6256     5b/pop-to-ebx
 6257     5a/pop-to-edx
 6258     59/pop-to-ecx
 6259     # . epilogue
 6260     89/<- %esp 5/r32/ebp
 6261     5d/pop-to-ebp
 6262     c3/return
 6263 
 6264 test-parse-var-with-type:
 6265     # . prologue
 6266     55/push-ebp
 6267     89/<- %ebp 4/r32/esp
 6268     # (eax..ecx) = "x:"
 6269     b8/copy-to-eax "x:"/imm32
 6270     8b/-> *eax 1/r32/ecx
 6271     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6272     05/add-to-eax 4/imm32
 6273     # var slice/ecx: slice = {eax, ecx}
 6274     51/push-ecx
 6275     50/push-eax
 6276     89/<- %ecx 4/r32/esp
 6277     # _test-input-stream contains "int"
 6278     (clear-stream _test-input-stream)
 6279     (write _test-input-stream "int")
 6280     # var v/edx: (handle var)
 6281     68/push 0/imm32
 6282     68/push 0/imm32
 6283     89/<- %edx 4/r32/esp
 6284     #
 6285     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6286     # var v-addr/edx: (addr var) = lookup(v)
 6287     (lookup *edx *(edx+4))  # => eax
 6288     89/<- %edx 0/r32/eax
 6289     # check v-addr->name
 6290     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6291     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 6292     # check v-addr->type
 6293     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6294     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 6295     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 6296     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 6297     # . epilogue
 6298     89/<- %esp 5/r32/ebp
 6299     5d/pop-to-ebp
 6300     c3/return
 6301 
 6302 test-parse-var-with-type-and-register:
 6303     # . prologue
 6304     55/push-ebp
 6305     89/<- %ebp 4/r32/esp
 6306     # (eax..ecx) = "x/eax:"
 6307     b8/copy-to-eax "x/eax:"/imm32
 6308     8b/-> *eax 1/r32/ecx
 6309     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6310     05/add-to-eax 4/imm32
 6311     # var slice/ecx: slice = {eax, ecx}
 6312     51/push-ecx
 6313     50/push-eax
 6314     89/<- %ecx 4/r32/esp
 6315     # _test-input-stream contains "int"
 6316     (clear-stream _test-input-stream)
 6317     (write _test-input-stream "int")
 6318     # var v/edx: (handle var)
 6319     68/push 0/imm32
 6320     68/push 0/imm32
 6321     89/<- %edx 4/r32/esp
 6322     #
 6323     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6324     # var v-addr/edx: (addr var) = lookup(v)
 6325     (lookup *edx *(edx+4))  # => eax
 6326     89/<- %edx 0/r32/eax
 6327     # check v-addr->name
 6328     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6329     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 6330     # check v-addr->register
 6331     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 6332     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 6333     # check v-addr->type
 6334     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6335     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 6336     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 6337     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 6338     # . epilogue
 6339     89/<- %esp 5/r32/ebp
 6340     5d/pop-to-ebp
 6341     c3/return
 6342 
 6343 test-parse-var-with-trailing-characters:
 6344     # . prologue
 6345     55/push-ebp
 6346     89/<- %ebp 4/r32/esp
 6347     # (eax..ecx) = "x:"
 6348     b8/copy-to-eax "x:"/imm32
 6349     8b/-> *eax 1/r32/ecx
 6350     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6351     05/add-to-eax 4/imm32
 6352     # var slice/ecx: slice = {eax, ecx}
 6353     51/push-ecx
 6354     50/push-eax
 6355     89/<- %ecx 4/r32/esp
 6356     # _test-input-stream contains "int,"
 6357     (clear-stream _test-input-stream)
 6358     (write _test-input-stream "int,")
 6359     # var v/edx: (handle var)
 6360     68/push 0/imm32
 6361     68/push 0/imm32
 6362     89/<- %edx 4/r32/esp
 6363     #
 6364     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6365     # var v-addr/edx: (addr var) = lookup(v)
 6366     (lookup *edx *(edx+4))  # => eax
 6367     89/<- %edx 0/r32/eax
 6368     # check v-addr->name
 6369     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6370     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 6371     # check v-addr->register
 6372     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 6373     # check v-addr->type
 6374     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6375     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 6376     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 6377     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 6378     # . epilogue
 6379     89/<- %esp 5/r32/ebp
 6380     5d/pop-to-ebp
 6381     c3/return
 6382 
 6383 test-parse-var-with-register-and-trailing-characters:
 6384     # . prologue
 6385     55/push-ebp
 6386     89/<- %ebp 4/r32/esp
 6387     # (eax..ecx) = "x/eax:"
 6388     b8/copy-to-eax "x/eax:"/imm32
 6389     8b/-> *eax 1/r32/ecx
 6390     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6391     05/add-to-eax 4/imm32
 6392     # var slice/ecx: slice = {eax, ecx}
 6393     51/push-ecx
 6394     50/push-eax
 6395     89/<- %ecx 4/r32/esp
 6396     # _test-input-stream contains "int,"
 6397     (clear-stream _test-input-stream)
 6398     (write _test-input-stream "int,")
 6399     # var v/edx: (handle var)
 6400     68/push 0/imm32
 6401     68/push 0/imm32
 6402     89/<- %edx 4/r32/esp
 6403     #
 6404     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6405     # var v-addr/edx: (addr var) = lookup(v)
 6406     (lookup *edx *(edx+4))  # => eax
 6407     89/<- %edx 0/r32/eax
 6408     # check v-addr->name
 6409     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6410     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 6411     # check v-addr->register
 6412     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 6413     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 6414     # check v-addr->type
 6415     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6416     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 6417     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 6418     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 6419     # . epilogue
 6420     89/<- %esp 5/r32/ebp
 6421     5d/pop-to-ebp
 6422     c3/return
 6423 
 6424 test-parse-var-with-compound-type:
 6425     # . prologue
 6426     55/push-ebp
 6427     89/<- %ebp 4/r32/esp
 6428     # (eax..ecx) = "x:"
 6429     b8/copy-to-eax "x:"/imm32
 6430     8b/-> *eax 1/r32/ecx
 6431     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6432     05/add-to-eax 4/imm32
 6433     # var slice/ecx: slice = {eax, ecx}
 6434     51/push-ecx
 6435     50/push-eax
 6436     89/<- %ecx 4/r32/esp
 6437     # _test-input-stream contains "(addr int)"
 6438     (clear-stream _test-input-stream)
 6439     (write _test-input-stream "(addr int)")
 6440     # var v/edx: (handle var)
 6441     68/push 0/imm32
 6442     68/push 0/imm32
 6443     89/<- %edx 4/r32/esp
 6444     #
 6445     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6446     # var v-addr/edx: (addr var) = lookup(v)
 6447     (lookup *edx *(edx+4))  # => eax
 6448     89/<- %edx 0/r32/eax
 6449     # check v-addr->name
 6450     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6451     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 6452     # check v-addr->register
 6453     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 6454     # - check v-addr->type
 6455     # var type/edx: (addr tree type-id) = var->type
 6456     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6457     89/<- %edx 0/r32/eax
 6458     # type is a non-atom
 6459     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 6460     # type->left == atom(addr)
 6461     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 6462     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 6463     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 6464     # type->right->left == atom(int)
 6465     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 6466     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 6467     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 6468     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 6469     # type->right->right == null
 6470     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 6471     # . epilogue
 6472     89/<- %esp 5/r32/ebp
 6473     5d/pop-to-ebp
 6474     c3/return
 6475 
 6476 # identifier starts with a letter or '$' or '_'
 6477 # no constraints at the moment on later letters
 6478 # all we really want to do so far is exclude '{', '}' and '->'
 6479 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 6480     # . prologue
 6481     55/push-ebp
 6482     89/<- %ebp 4/r32/esp
 6483     # if (slice-empty?(in)) return false
 6484     (slice-empty? *(ebp+8))  # => eax
 6485     3d/compare-eax-and 0/imm32/false
 6486     75/jump-if-!= $is-identifier?:false/disp8
 6487     # var c/eax: byte = *in->start
 6488     8b/-> *(ebp+8) 0/r32/eax
 6489     8b/-> *eax 0/r32/eax
 6490     8a/copy-byte *eax 0/r32/AL
 6491     81 4/subop/and %eax 0xff/imm32
 6492     # if (c == '$') return true
 6493     3d/compare-eax-and 0x24/imm32/$
 6494     74/jump-if-= $is-identifier?:true/disp8
 6495     # if (c == '_') return true
 6496     3d/compare-eax-and 0x5f/imm32/_
 6497     74/jump-if-= $is-identifier?:true/disp8
 6498     # drop case
 6499     25/and-eax-with 0x5f/imm32
 6500     # if (c < 'A') return false
 6501     3d/compare-eax-and 0x41/imm32/A
 6502     7c/jump-if-< $is-identifier?:false/disp8
 6503     # if (c > 'Z') return false
 6504     3d/compare-eax-and 0x5a/imm32/Z
 6505     7f/jump-if-> $is-identifier?:false/disp8
 6506     # otherwise return true
 6507 $is-identifier?:true:
 6508     b8/copy-to-eax 1/imm32/true
 6509     eb/jump $is-identifier?:end/disp8
 6510 $is-identifier?:false:
 6511     b8/copy-to-eax 0/imm32/false
 6512 $is-identifier?:end:
 6513     # . epilogue
 6514     89/<- %esp 5/r32/ebp
 6515     5d/pop-to-ebp
 6516     c3/return
 6517 
 6518 test-is-identifier-dollar:
 6519     # . prologue
 6520     55/push-ebp
 6521     89/<- %ebp 4/r32/esp
 6522     # (eax..ecx) = "$a"
 6523     b8/copy-to-eax "$a"/imm32
 6524     8b/-> *eax 1/r32/ecx
 6525     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6526     05/add-to-eax 4/imm32
 6527     # var slice/ecx: slice = {eax, ecx}
 6528     51/push-ecx
 6529     50/push-eax
 6530     89/<- %ecx 4/r32/esp
 6531     #
 6532     (is-identifier? %ecx)
 6533     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 6534     # . epilogue
 6535     89/<- %esp 5/r32/ebp
 6536     5d/pop-to-ebp
 6537     c3/return
 6538 
 6539 test-is-identifier-underscore:
 6540     # . prologue
 6541     55/push-ebp
 6542     89/<- %ebp 4/r32/esp
 6543     # (eax..ecx) = "_a"
 6544     b8/copy-to-eax "_a"/imm32
 6545     8b/-> *eax 1/r32/ecx
 6546     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6547     05/add-to-eax 4/imm32
 6548     # var slice/ecx: slice = {eax, ecx}
 6549     51/push-ecx
 6550     50/push-eax
 6551     89/<- %ecx 4/r32/esp
 6552     #
 6553     (is-identifier? %ecx)
 6554     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 6555     # . epilogue
 6556     89/<- %esp 5/r32/ebp
 6557     5d/pop-to-ebp
 6558     c3/return
 6559 
 6560 test-is-identifier-a:
 6561     # . prologue
 6562     55/push-ebp
 6563     89/<- %ebp 4/r32/esp
 6564     # (eax..ecx) = "a$"
 6565     b8/copy-to-eax "a$"/imm32
 6566     8b/-> *eax 1/r32/ecx
 6567     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6568     05/add-to-eax 4/imm32
 6569     # var slice/ecx: slice = {eax, ecx}
 6570     51/push-ecx
 6571     50/push-eax
 6572     89/<- %ecx 4/r32/esp
 6573     #
 6574     (is-identifier? %ecx)
 6575     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 6576     # . epilogue
 6577     89/<- %esp 5/r32/ebp
 6578     5d/pop-to-ebp
 6579     c3/return
 6580 
 6581 test-is-identifier-z:
 6582     # . prologue
 6583     55/push-ebp
 6584     89/<- %ebp 4/r32/esp
 6585     # (eax..ecx) = "z$"
 6586     b8/copy-to-eax "z$"/imm32
 6587     8b/-> *eax 1/r32/ecx
 6588     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6589     05/add-to-eax 4/imm32
 6590     # var slice/ecx: slice = {eax, ecx}
 6591     51/push-ecx
 6592     50/push-eax
 6593     89/<- %ecx 4/r32/esp
 6594     #
 6595     (is-identifier? %ecx)
 6596     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 6597     # . epilogue
 6598     89/<- %esp 5/r32/ebp
 6599     5d/pop-to-ebp
 6600     c3/return
 6601 
 6602 test-is-identifier-A:
 6603     # . prologue
 6604     55/push-ebp
 6605     89/<- %ebp 4/r32/esp
 6606     # (eax..ecx) = "A$"
 6607     b8/copy-to-eax "A$"/imm32
 6608     8b/-> *eax 1/r32/ecx
 6609     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6610     05/add-to-eax 4/imm32
 6611     # var slice/ecx: slice = {eax, ecx}
 6612     51/push-ecx
 6613     50/push-eax
 6614     89/<- %ecx 4/r32/esp
 6615     #
 6616     (is-identifier? %ecx)
 6617     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 6618     # . epilogue
 6619     89/<- %esp 5/r32/ebp
 6620     5d/pop-to-ebp
 6621     c3/return
 6622 
 6623 test-is-identifier-Z:
 6624     # . prologue
 6625     55/push-ebp
 6626     89/<- %ebp 4/r32/esp
 6627     # (eax..ecx) = "Z$"
 6628     b8/copy-to-eax "Z$"/imm32
 6629     8b/-> *eax 1/r32/ecx
 6630     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6631     05/add-to-eax 4/imm32
 6632     # var slice/ecx: slice = {eax, ecx}
 6633     51/push-ecx
 6634     50/push-eax
 6635     89/<- %ecx 4/r32/esp
 6636     #
 6637     (is-identifier? %ecx)
 6638     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 6639     # . epilogue
 6640     89/<- %esp 5/r32/ebp
 6641     5d/pop-to-ebp
 6642     c3/return
 6643 
 6644 test-is-identifier-at:
 6645     # character before 'A' is invalid
 6646     # . prologue
 6647     55/push-ebp
 6648     89/<- %ebp 4/r32/esp
 6649     # (eax..ecx) = "@a"
 6650     b8/copy-to-eax "@a"/imm32
 6651     8b/-> *eax 1/r32/ecx
 6652     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6653     05/add-to-eax 4/imm32
 6654     # var slice/ecx: slice = {eax, ecx}
 6655     51/push-ecx
 6656     50/push-eax
 6657     89/<- %ecx 4/r32/esp
 6658     #
 6659     (is-identifier? %ecx)
 6660     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 6661     # . epilogue
 6662     89/<- %esp 5/r32/ebp
 6663     5d/pop-to-ebp
 6664     c3/return
 6665 
 6666 test-is-identifier-square-bracket:
 6667     # character after 'Z' is invalid
 6668     # . prologue
 6669     55/push-ebp
 6670     89/<- %ebp 4/r32/esp
 6671     # (eax..ecx) = "[a"
 6672     b8/copy-to-eax "[a"/imm32
 6673     8b/-> *eax 1/r32/ecx
 6674     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6675     05/add-to-eax 4/imm32
 6676     # var slice/ecx: slice = {eax, ecx}
 6677     51/push-ecx
 6678     50/push-eax
 6679     89/<- %ecx 4/r32/esp
 6680     #
 6681     (is-identifier? %ecx)
 6682     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 6683     # . epilogue
 6684     89/<- %esp 5/r32/ebp
 6685     5d/pop-to-ebp
 6686     c3/return
 6687 
 6688 test-is-identifier-backtick:
 6689     # character before 'a' is invalid
 6690     # . prologue
 6691     55/push-ebp
 6692     89/<- %ebp 4/r32/esp
 6693     # (eax..ecx) = "`a"
 6694     b8/copy-to-eax "`a"/imm32
 6695     8b/-> *eax 1/r32/ecx
 6696     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6697     05/add-to-eax 4/imm32
 6698     # var slice/ecx: slice = {eax, ecx}
 6699     51/push-ecx
 6700     50/push-eax
 6701     89/<- %ecx 4/r32/esp
 6702     #
 6703     (is-identifier? %ecx)
 6704     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 6705     # . epilogue
 6706     89/<- %esp 5/r32/ebp
 6707     5d/pop-to-ebp
 6708     c3/return
 6709 
 6710 test-is-identifier-curly-brace-open:
 6711     # character after 'z' is invalid; also used for blocks
 6712     # . prologue
 6713     55/push-ebp
 6714     89/<- %ebp 4/r32/esp
 6715     # (eax..ecx) = "{a"
 6716     b8/copy-to-eax "{a"/imm32
 6717     8b/-> *eax 1/r32/ecx
 6718     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6719     05/add-to-eax 4/imm32
 6720     # var slice/ecx: slice = {eax, ecx}
 6721     51/push-ecx
 6722     50/push-eax
 6723     89/<- %ecx 4/r32/esp
 6724     #
 6725     (is-identifier? %ecx)
 6726     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 6727     # . epilogue
 6728     89/<- %esp 5/r32/ebp
 6729     5d/pop-to-ebp
 6730     c3/return
 6731 
 6732 test-is-identifier-curly-brace-close:
 6733     # . prologue
 6734     55/push-ebp
 6735     89/<- %ebp 4/r32/esp
 6736     # (eax..ecx) = "}a"
 6737     b8/copy-to-eax "}a"/imm32
 6738     8b/-> *eax 1/r32/ecx
 6739     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6740     05/add-to-eax 4/imm32
 6741     # var slice/ecx: slice = {eax, ecx}
 6742     51/push-ecx
 6743     50/push-eax
 6744     89/<- %ecx 4/r32/esp
 6745     #
 6746     (is-identifier? %ecx)
 6747     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 6748     # . epilogue
 6749     89/<- %esp 5/r32/ebp
 6750     5d/pop-to-ebp
 6751     c3/return
 6752 
 6753 test-is-identifier-hyphen:
 6754     # disallow leading '-' since '->' has special meaning
 6755     # . prologue
 6756     55/push-ebp
 6757     89/<- %ebp 4/r32/esp
 6758     # (eax..ecx) = "-a"
 6759     b8/copy-to-eax "-a"/imm32
 6760     8b/-> *eax 1/r32/ecx
 6761     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6762     05/add-to-eax 4/imm32
 6763     # var slice/ecx: slice = {eax, ecx}
 6764     51/push-ecx
 6765     50/push-eax
 6766     89/<- %ecx 4/r32/esp
 6767     #
 6768     (is-identifier? %ecx)
 6769     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 6770     # . epilogue
 6771     89/<- %esp 5/r32/ebp
 6772     5d/pop-to-ebp
 6773     c3/return
 6774 
 6775 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6776     # . prologue
 6777     55/push-ebp
 6778     89/<- %ebp 4/r32/esp
 6779     # . save registers
 6780     50/push-eax
 6781     56/push-esi
 6782     57/push-edi
 6783     # esi = in
 6784     8b/-> *(ebp+8) 6/r32/esi
 6785     # edi = out
 6786     8b/-> *(ebp+0xc) 7/r32/edi
 6787     # initialize some global state
 6788     c7 0/subop/copy *Curr-block-depth 1/imm32
 6789     # parse-mu-block(in, vars, out, out->body)
 6790     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 6791     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 6792 $populate-mu-function-body:end:
 6793     # . restore registers
 6794     5f/pop-to-edi
 6795     5e/pop-to-esi
 6796     58/pop-to-eax
 6797     # . epilogue
 6798     89/<- %esp 5/r32/ebp
 6799     5d/pop-to-ebp
 6800     c3/return
 6801 
 6802 # parses a block, assuming that the leading '{' has already been read by the caller
 6803 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)
 6804     # pseudocode:
 6805     #   var line: (stream byte 512)
 6806     #   var word-slice: slice
 6807     #   allocate(Heap, Stmt-size, out)
 6808     #   var out-addr: (addr block) = lookup(*out)
 6809     #   out-addr->tag = 0/block
 6810     #   out-addr->var = some unique name
 6811     #   push(vars, {out-addr->var, false})
 6812     #   while true                                  # line loop
 6813     #     clear-stream(line)
 6814     #     read-line-buffered(in, line)
 6815     #     if (line->write == 0) break               # end of file
 6816     #     word-slice = next-mu-token(line)
 6817     #     if slice-empty?(word-slice)               # end of line
 6818     #       continue
 6819     #     else if slice-starts-with?(word-slice, "#")
 6820     #       continue
 6821     #     else if slice-equal?(word-slice, "{")
 6822     #       assert(no-tokens-in(line))
 6823     #       block = parse-mu-block(in, vars, fn)
 6824     #       append-to-block(out-addr, block)
 6825     #     else if slice-equal?(word-slice, "}")
 6826     #       break
 6827     #     else if slice-ends-with?(word-slice, ":")
 6828     #       # TODO: error-check the rest of 'line'
 6829     #       --word-slice->end to skip ':'
 6830     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 6831     #       append-to-block(out-addr, named-block)
 6832     #     else if slice-equal?(word-slice, "var")
 6833     #       var-def = parse-mu-var-def(line, vars, fn)
 6834     #       append-to-block(out-addr, var-def)
 6835     #     else
 6836     #       stmt = parse-mu-stmt(line, vars, fn)
 6837     #       append-to-block(out-addr, stmt)
 6838     #   pop(vars)
 6839     #
 6840     # . prologue
 6841     55/push-ebp
 6842     89/<- %ebp 4/r32/esp
 6843     # . save registers
 6844     50/push-eax
 6845     51/push-ecx
 6846     52/push-edx
 6847     53/push-ebx
 6848     57/push-edi
 6849     # var line/ecx: (stream byte 512)
 6850     81 5/subop/subtract %esp 0x200/imm32
 6851     68/push 0x200/imm32/size
 6852     68/push 0/imm32/read
 6853     68/push 0/imm32/write
 6854     89/<- %ecx 4/r32/esp
 6855     # var word-slice/edx: slice
 6856     68/push 0/imm32/end
 6857     68/push 0/imm32/start
 6858     89/<- %edx 4/r32/esp
 6859     # allocate into out
 6860     (allocate Heap *Stmt-size *(ebp+0x14))
 6861     # var out-addr/edi: (addr block) = lookup(*out)
 6862     8b/-> *(ebp+0x14) 7/r32/edi
 6863     (lookup *edi *(edi+4))  # => eax
 6864     89/<- %edi 0/r32/eax
 6865     # out-addr->tag is 0 (block) by default
 6866     # set out-addr->var
 6867     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 6868     (new-block-name *(ebp+0x10) %eax)
 6869     # push(vars, out-addr->var)
 6870     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 6871     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 6872     (push *(ebp+0xc) 0)  # false
 6873     # increment *Curr-block-depth
 6874     ff 0/subop/increment *Curr-block-depth
 6875     {
 6876 $parse-mu-block:line-loop:
 6877       # line = read-line-buffered(in)
 6878       (clear-stream %ecx)
 6879       (read-line-buffered *(ebp+8) %ecx)
 6880 #?       (write-buffered Stderr "line: ")
 6881 #?       (write-stream-data Stderr %ecx)
 6882 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 6883 #?       (flush Stderr)
 6884 #?       (rewind-stream %ecx)
 6885       # if (line->write == 0) break
 6886       81 7/subop/compare *ecx 0/imm32
 6887       0f 84/jump-if-= break/disp32
 6888 #?       (write-buffered Stderr "vars:\n")
 6889 #?       (dump-vars *(ebp+0xc))
 6890       # word-slice = next-mu-token(line)
 6891       (next-mu-token %ecx %edx)
 6892 #?       (write-buffered Stderr "word: ")
 6893 #?       (write-slice-buffered Stderr %edx)
 6894 #?       (write-buffered Stderr Newline)
 6895 #?       (flush Stderr)
 6896       # if slice-empty?(word-slice) continue
 6897       (slice-empty? %edx)
 6898       3d/compare-eax-and 0/imm32/false
 6899       0f 85/jump-if-!= loop/disp32
 6900       # if (slice-starts-with?(word-slice, '#') continue
 6901       # . eax = *word-slice->start
 6902       8b/-> *edx 0/r32/eax
 6903       8a/copy-byte *eax 0/r32/AL
 6904       81 4/subop/and %eax 0xff/imm32
 6905       # . if (eax == '#') continue
 6906       3d/compare-eax-and 0x23/imm32/hash
 6907       0f 84/jump-if-= loop/disp32
 6908       # if slice-equal?(word-slice, "{")
 6909       {
 6910 $parse-mu-block:check-for-block:
 6911         (slice-equal? %edx "{")
 6912         3d/compare-eax-and 0/imm32/false
 6913         74/jump-if-= break/disp8
 6914         (check-no-tokens-left %ecx)
 6915         # parse new block and append
 6916         # . var tmp/eax: (handle block)
 6917         68/push 0/imm32
 6918         68/push 0/imm32
 6919         89/<- %eax 4/r32/esp
 6920         # .
 6921         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6922         (append-to-block Heap %edi  *eax *(eax+4))
 6923         # . reclaim tmp
 6924         81 0/subop/add %esp 8/imm32
 6925         # .
 6926         e9/jump $parse-mu-block:line-loop/disp32
 6927       }
 6928       # if slice-equal?(word-slice, "}") break
 6929 $parse-mu-block:check-for-end:
 6930       (slice-equal? %edx "}")
 6931       3d/compare-eax-and 0/imm32/false
 6932       0f 85/jump-if-!= break/disp32
 6933       # if slice-ends-with?(word-slice, ":") parse named block and append
 6934       {
 6935 $parse-mu-block:check-for-named-block:
 6936         # . eax = *(word-slice->end-1)
 6937         8b/-> *(edx+4) 0/r32/eax
 6938         48/decrement-eax
 6939         8a/copy-byte *eax 0/r32/AL
 6940         81 4/subop/and %eax 0xff/imm32
 6941         # . if (eax != ':') break
 6942         3d/compare-eax-and 0x3a/imm32/colon
 6943         0f 85/jump-if-!= break/disp32
 6944         # TODO: error-check the rest of 'line'
 6945         #
 6946         # skip ':'
 6947         ff 1/subop/decrement *(edx+4)  # Slice-end
 6948         # var tmp/eax: (handle block)
 6949         68/push 0/imm32
 6950         68/push 0/imm32
 6951         89/<- %eax 4/r32/esp
 6952         #
 6953         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6954         (append-to-block Heap %edi  *eax *(eax+4))
 6955         # reclaim tmp
 6956         81 0/subop/add %esp 8/imm32
 6957         #
 6958         e9/jump $parse-mu-block:line-loop/disp32
 6959       }
 6960       # if slice-equal?(word-slice, "var")
 6961       {
 6962 $parse-mu-block:check-for-var:
 6963         (slice-equal? %edx "var")
 6964         3d/compare-eax-and 0/imm32/false
 6965         74/jump-if-= break/disp8
 6966         # var tmp/eax: (handle block)
 6967         68/push 0/imm32
 6968         68/push 0/imm32
 6969         89/<- %eax 4/r32/esp
 6970         #
 6971         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 6972         (append-to-block Heap %edi  *eax *(eax+4))
 6973         # reclaim tmp
 6974         81 0/subop/add %esp 8/imm32
 6975         #
 6976         e9/jump $parse-mu-block:line-loop/disp32
 6977       }
 6978 $parse-mu-block:regular-stmt:
 6979       # otherwise
 6980       # var tmp/eax: (handle block)
 6981       68/push 0/imm32
 6982       68/push 0/imm32
 6983       89/<- %eax 4/r32/esp
 6984       #
 6985       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6986       (append-to-block Heap %edi  *eax *(eax+4))
 6987       # reclaim tmp
 6988       81 0/subop/add %esp 8/imm32
 6989       #
 6990       e9/jump loop/disp32
 6991     } # end line loop
 6992     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 6993     # decrement *Curr-block-depth
 6994     ff 1/subop/decrement *Curr-block-depth
 6995     # pop(vars)
 6996     (pop *(ebp+0xc))  # => eax
 6997     (pop *(ebp+0xc))  # => eax
 6998     (pop *(ebp+0xc))  # => eax
 6999 $parse-mu-block:end:
 7000     # . reclaim locals
 7001     81 0/subop/add %esp 0x214/imm32
 7002     # . restore registers
 7003     5f/pop-to-edi
 7004     5b/pop-to-ebx
 7005     5a/pop-to-edx
 7006     59/pop-to-ecx
 7007     58/pop-to-eax
 7008     # . epilogue
 7009     89/<- %esp 5/r32/ebp
 7010     5d/pop-to-ebp
 7011     c3/return
 7012 
 7013 $parse-mu-block:abort:
 7014     # error("'{' or '}' should be on its own line, but got '")
 7015     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 7016     (rewind-stream %ecx)
 7017     (write-stream-data *(ebp+0x18) %ecx)
 7018     (write-buffered *(ebp+0x18) "'\n")
 7019     (flush *(ebp+0x18))
 7020     (stop *(ebp+0x1c) 1)
 7021     # never gets here
 7022 
 7023 new-block-name:  # fn: (addr function), out: (addr handle var)
 7024     # . prologue
 7025     55/push-ebp
 7026     89/<- %ebp 4/r32/esp
 7027     # . save registers
 7028     50/push-eax
 7029     51/push-ecx
 7030     52/push-edx
 7031     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 7032     8b/-> *(ebp+8) 0/r32/eax
 7033     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7034     8b/-> *eax 0/r32/eax  # String-size
 7035     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 7036     89/<- %ecx 0/r32/eax
 7037     # var name/edx: (stream byte n)
 7038     29/subtract-from %esp 1/r32/ecx
 7039     ff 6/subop/push %ecx
 7040     68/push 0/imm32/read
 7041     68/push 0/imm32/write
 7042     89/<- %edx 4/r32/esp
 7043     (clear-stream %edx)
 7044     # eax = fn->name
 7045     8b/-> *(ebp+8) 0/r32/eax
 7046     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7047     # construct result using Next-block-index (and increment it)
 7048     (write %edx "$")
 7049     (write %edx %eax)
 7050     (write %edx ":")
 7051     (print-int32 %edx *Next-block-index)
 7052     ff 0/subop/increment *Next-block-index
 7053     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 7054     # . eax = name->write
 7055     8b/-> *edx 0/r32/eax
 7056     # . edx = name->data
 7057     8d/copy-address *(edx+0xc) 2/r32/edx
 7058     # . eax = name->write + name->data
 7059     01/add-to %eax 2/r32/edx
 7060     # . push {edx, eax}
 7061     ff 6/subop/push %eax
 7062     ff 6/subop/push %edx
 7063     89/<- %eax 4/r32/esp
 7064     # out = new literal(s)
 7065     (new-literal Heap %eax *(ebp+0xc))
 7066 #?     8b/-> *(ebp+0xc) 0/r32/eax
 7067 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 7068 #?     (print-int32-buffered Stderr *(eax+8))
 7069 #?     (write-buffered Stderr " for var ")
 7070 #?     (print-int32-buffered Stderr %eax)
 7071 #?     (write-buffered Stderr Newline)
 7072 #?     (flush Stderr)
 7073 $new-block-name:end:
 7074     # . reclaim locals
 7075     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 7076     81 0/subop/add %ecx 8/imm32  # slice
 7077     01/add-to %esp 1/r32/ecx
 7078     # . restore registers
 7079     5a/pop-to-edx
 7080     59/pop-to-ecx
 7081     58/pop-to-eax
 7082     # . epilogue
 7083     89/<- %esp 5/r32/ebp
 7084     5d/pop-to-ebp
 7085     c3/return
 7086 
 7087 check-no-tokens-left:  # line: (addr stream byte)
 7088     # . prologue
 7089     55/push-ebp
 7090     89/<- %ebp 4/r32/esp
 7091     # . save registers
 7092     50/push-eax
 7093     51/push-ecx
 7094     # var s/ecx: slice
 7095     68/push 0/imm32/end
 7096     68/push 0/imm32/start
 7097     89/<- %ecx 4/r32/esp
 7098     #
 7099     (next-mu-token *(ebp+8) %ecx)
 7100     # if slice-empty?(s) return
 7101     (slice-empty? %ecx)
 7102     3d/compare-eax-and 0/imm32/false
 7103     75/jump-if-!= $check-no-tokens-left:end/disp8
 7104     # if (slice-starts-with?(s, '#') return
 7105     # . eax = *s->start
 7106     8b/-> *edx 0/r32/eax
 7107     8a/copy-byte *eax 0/r32/AL
 7108     81 4/subop/and %eax 0xff/imm32
 7109     # . if (eax == '#') continue
 7110     3d/compare-eax-and 0x23/imm32/hash
 7111     74/jump-if-= $check-no-tokens-left:end/disp8
 7112     # abort
 7113     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 7114     (rewind-stream %ecx)
 7115     (write-stream 2 %ecx)
 7116     (write-buffered Stderr "'\n")
 7117     (flush Stderr)
 7118     # . syscall(exit, 1)
 7119     bb/copy-to-ebx  1/imm32
 7120     e8/call syscall_exit/disp32
 7121     # never gets here
 7122 $check-no-tokens-left:end:
 7123     # . reclaim locals
 7124     81 0/subop/add %esp 8/imm32
 7125     # . restore registers
 7126     59/pop-to-ecx
 7127     58/pop-to-eax
 7128     # . epilogue
 7129     89/<- %esp 5/r32/ebp
 7130     5d/pop-to-ebp
 7131     c3/return
 7132 
 7133 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)
 7134     # pseudocode:
 7135     #   var v: (handle var)
 7136     #   new-literal(name, v)
 7137     #   push(vars, {v, false})
 7138     #   parse-mu-block(in, vars, fn, out)
 7139     #   pop(vars)
 7140     #   out->tag = block
 7141     #   out->var = v
 7142     #
 7143     # . prologue
 7144     55/push-ebp
 7145     89/<- %ebp 4/r32/esp
 7146     # . save registers
 7147     50/push-eax
 7148     51/push-ecx
 7149     57/push-edi
 7150     # var v/ecx: (handle var)
 7151     68/push 0/imm32
 7152     68/push 0/imm32
 7153     89/<- %ecx 4/r32/esp
 7154     #
 7155     (new-literal Heap *(ebp+8) %ecx)
 7156     # push(vars, v)
 7157     (push *(ebp+0x10) *ecx)
 7158     (push *(ebp+0x10) *(ecx+4))
 7159     (push *(ebp+0x10) 0)  # false
 7160     #
 7161     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 7162     # pop v off vars
 7163     (pop *(ebp+0x10))  # => eax
 7164     (pop *(ebp+0x10))  # => eax
 7165     (pop *(ebp+0x10))  # => eax
 7166     # var out-addr/edi: (addr stmt) = lookup(*out)
 7167     8b/-> *(ebp+0x18) 7/r32/edi
 7168     (lookup *edi *(edi+4))  # => eax
 7169     89/<- %edi 0/r32/eax
 7170     # out-addr->tag = named-block
 7171     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 7172     # out-addr->var = v
 7173     8b/-> *ecx 0/r32/eax
 7174     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 7175     8b/-> *(ecx+4) 0/r32/eax
 7176     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 7177 $parse-mu-named-block:end:
 7178     # . reclaim locals
 7179     81 0/subop/add %esp 8/imm32
 7180     # . restore registers
 7181     5f/pop-to-edi
 7182     59/pop-to-ecx
 7183     58/pop-to-eax
 7184     # . epilogue
 7185     89/<- %esp 5/r32/ebp
 7186     5d/pop-to-ebp
 7187     c3/return
 7188 
 7189 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)
 7190     # . prologue
 7191     55/push-ebp
 7192     89/<- %ebp 4/r32/esp
 7193     # . save registers
 7194     50/push-eax
 7195     51/push-ecx
 7196     52/push-edx
 7197     53/push-ebx
 7198     57/push-edi
 7199     # edi = out
 7200     8b/-> *(ebp+0x10) 7/r32/edi
 7201     # var word-slice/ecx: slice
 7202     68/push 0/imm32/end
 7203     68/push 0/imm32/start
 7204     89/<- %ecx 4/r32/esp
 7205     # var v/edx: (handle var)
 7206     68/push 0/imm32
 7207     68/push 0/imm32
 7208     89/<- %edx 4/r32/esp
 7209     # v = parse-var-with-type(next-mu-token(line))
 7210     (next-mu-token *(ebp+8) %ecx)
 7211     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 7212     # var v-addr/eax: (addr var)
 7213     (lookup *edx *(edx+4))  # => eax
 7214     # v->block-depth = *Curr-block-depth
 7215     8b/-> *Curr-block-depth 3/r32/ebx
 7216     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 7217     # either v has no register and there's no more to this line
 7218     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 7219     3d/compare-eax-and 0/imm32
 7220     {
 7221       75/jump-if-!= break/disp8
 7222       # TODO: disallow vars of type 'byte' on the stack
 7223       # ensure that there's nothing else on this line
 7224       (next-mu-token *(ebp+8) %ecx)
 7225       (slice-empty? %ecx)  # => eax
 7226       3d/compare-eax-and 0/imm32/false
 7227       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 7228       #
 7229       (new-var-def Heap  *edx *(edx+4)  %edi)
 7230       e9/jump $parse-mu-var-def:update-vars/disp32
 7231     }
 7232     # or v has a register and there's more to this line
 7233     {
 7234       0f 84/jump-if-= break/disp32
 7235       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 7236       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 7237       # ensure that the next word is '<-'
 7238       (next-mu-token *(ebp+8) %ecx)
 7239       (slice-equal? %ecx "<-")  # => eax
 7240       3d/compare-eax-and 0/imm32/false
 7241       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 7242       #
 7243       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 7244       (lookup *edi *(edi+4))  # => eax
 7245       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 7246     }
 7247 $parse-mu-var-def:update-vars:
 7248     # push 'v' at end of function
 7249     (push *(ebp+0xc) *edx)
 7250     (push *(ebp+0xc) *(edx+4))
 7251     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 7252 $parse-mu-var-def:end:
 7253     # . reclaim locals
 7254     81 0/subop/add %esp 0x10/imm32
 7255     # . restore registers
 7256     5f/pop-to-edi
 7257     5b/pop-to-ebx
 7258     5a/pop-to-edx
 7259     59/pop-to-ecx
 7260     58/pop-to-eax
 7261     # . epilogue
 7262     89/<- %esp 5/r32/ebp
 7263     5d/pop-to-ebp
 7264     c3/return
 7265 
 7266 $parse-mu-var-def:error1:
 7267     (rewind-stream *(ebp+8))
 7268     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 7269     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 7270     (flush *(ebp+0x18))
 7271     (write-stream-data *(ebp+0x18) *(ebp+8))
 7272     (write-buffered *(ebp+0x18) "'\n")
 7273     (flush *(ebp+0x18))
 7274     (stop *(ebp+0x1c) 1)
 7275     # never gets here
 7276 
 7277 $parse-mu-var-def:error2:
 7278     (rewind-stream *(ebp+8))
 7279     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 7280     (write-buffered *(ebp+0x18) "fn ")
 7281     8b/-> *(ebp+0x14) 0/r32/eax
 7282     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7283     (write-buffered *(ebp+0x18) %eax)
 7284     (write-buffered *(ebp+0x18) ": var ")
 7285     # var v-addr/eax: (addr var) = lookup(v)
 7286     (lookup *edx *(edx+4))  # => eax
 7287     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7288     (write-buffered *(ebp+0x18) %eax)
 7289     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 7290     (flush *(ebp+0x18))
 7291     (stop *(ebp+0x1c) 1)
 7292     # never gets here
 7293 
 7294 test-parse-mu-var-def:
 7295     # 'var n: int'
 7296     # . prologue
 7297     55/push-ebp
 7298     89/<- %ebp 4/r32/esp
 7299     # setup
 7300     (clear-stream _test-input-stream)
 7301     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 7302     c7 0/subop/copy *Curr-block-depth 1/imm32
 7303     # var out/esi: (handle stmt)
 7304     68/push 0/imm32
 7305     68/push 0/imm32
 7306     89/<- %esi 4/r32/esp
 7307     # var vars/ecx: (stack (addr var) 16)
 7308     81 5/subop/subtract %esp 0xc0/imm32
 7309     68/push 0xc0/imm32/size
 7310     68/push 0/imm32/top
 7311     89/<- %ecx 4/r32/esp
 7312     (clear-stack %ecx)
 7313     # convert
 7314     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 7315     # var out-addr/esi: (addr stmt)
 7316     (lookup *esi *(esi+4))  # => eax
 7317     89/<- %esi 0/r32/eax
 7318     #
 7319     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 7320     # var v/ecx: (addr var) = lookup(out->var)
 7321     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 7322     89/<- %ecx 0/r32/eax
 7323     # v->name
 7324     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 7325     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 7326     # v->register
 7327     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 7328     # v->block-depth
 7329     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 7330     # v->type == int
 7331     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7332     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 7333     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 7334     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 7335     # . epilogue
 7336     89/<- %esp 5/r32/ebp
 7337     5d/pop-to-ebp
 7338     c3/return
 7339 
 7340 test-parse-mu-reg-var-def:
 7341     # 'var n/eax: int <- copy 0'
 7342     # . prologue
 7343     55/push-ebp
 7344     89/<- %ebp 4/r32/esp
 7345     # setup
 7346     (clear-stream _test-input-stream)
 7347     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 7348     c7 0/subop/copy *Curr-block-depth 1/imm32
 7349     # var out/esi: (handle stmt)
 7350     68/push 0/imm32
 7351     68/push 0/imm32
 7352     89/<- %esi 4/r32/esp
 7353     # var vars/ecx: (stack (addr var) 16)
 7354     81 5/subop/subtract %esp 0xc0/imm32
 7355     68/push 0xc0/imm32/size
 7356     68/push 0/imm32/top
 7357     89/<- %ecx 4/r32/esp
 7358     (clear-stack %ecx)
 7359     # convert
 7360     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 7361     # var out-addr/esi: (addr stmt)
 7362     (lookup *esi *(esi+4))  # => eax
 7363     89/<- %esi 0/r32/eax
 7364     #
 7365     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 7366     # var v/ecx: (addr var) = lookup(out->outputs->value)
 7367     # . eax: (addr stmt-var) = lookup(out->outputs)
 7368     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 7369     # .
 7370     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 7371     # . eax: (addr var) = lookup(eax->value)
 7372     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7373     # . ecx = eax
 7374     89/<- %ecx 0/r32/eax
 7375     # v->name
 7376     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 7377     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 7378     # v->register
 7379     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 7380     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 7381     # v->block-depth
 7382     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 7383     # v->type == int
 7384     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7385     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 7386     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 7387     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 7388     # . epilogue
 7389     89/<- %esp 5/r32/ebp
 7390     5d/pop-to-ebp
 7391     c3/return
 7392 
 7393 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)
 7394     # Carefully push any outputs on the vars stack _after_ reading the inputs
 7395     # that may conflict with them.
 7396     #
 7397     # The only situation in which outputs are pushed here (when it's not a
 7398     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 7399     # output is a function output.
 7400     #
 7401     # pseudocode:
 7402     #   var name: slice
 7403     #   allocate(Heap, Stmt-size, out)
 7404     #   var out-addr: (addr stmt) = lookup(*out)
 7405     #   out-addr->tag = stmt
 7406     #   if stmt-has-outputs?(line)
 7407     #     while true
 7408     #       name = next-mu-token(line)
 7409     #       if (name == '<-') break
 7410     #       assert(is-identifier?(name))
 7411     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 7412     #       out-addr->outputs = append(v, out-addr->outputs)
 7413     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 7414     #   for output in stmt->outputs:
 7415     #     maybe-define-var(output, vars)
 7416     #
 7417     # . prologue
 7418     55/push-ebp
 7419     89/<- %ebp 4/r32/esp
 7420     # . save registers
 7421     50/push-eax
 7422     51/push-ecx
 7423     52/push-edx
 7424     53/push-ebx
 7425     57/push-edi
 7426     # var name/ecx: slice
 7427     68/push 0/imm32/end
 7428     68/push 0/imm32/start
 7429     89/<- %ecx 4/r32/esp
 7430     # var is-deref?/edx: boolean = false
 7431     ba/copy-to-edx 0/imm32/false
 7432     # var v: (handle var)
 7433     68/push 0/imm32
 7434     68/push 0/imm32
 7435     89/<- %ebx 4/r32/esp
 7436     #
 7437     (allocate Heap *Stmt-size *(ebp+0x14))
 7438     # var out-addr/edi: (addr stmt) = lookup(*out)
 7439     8b/-> *(ebp+0x14) 7/r32/edi
 7440     (lookup *edi *(edi+4))  # => eax
 7441     89/<- %edi 0/r32/eax
 7442     # out-addr->tag = 1/stmt
 7443     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 7444     {
 7445       (stmt-has-outputs? *(ebp+8))
 7446       3d/compare-eax-and 0/imm32/false
 7447       0f 84/jump-if-= break/disp32
 7448       {
 7449 $parse-mu-stmt:read-outputs:
 7450         # name = next-mu-token(line)
 7451         (next-mu-token *(ebp+8) %ecx)
 7452         # if slice-empty?(word-slice) break
 7453         (slice-empty? %ecx)  # => eax
 7454         3d/compare-eax-and 0/imm32/false
 7455         0f 85/jump-if-!= break/disp32
 7456         # if (name == "<-") break
 7457         (slice-equal? %ecx "<-")  # => eax
 7458         3d/compare-eax-and 0/imm32/false
 7459         0f 85/jump-if-!= break/disp32
 7460         # is-deref? = false
 7461         ba/copy-to-edx 0/imm32/false
 7462         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 7463         8b/-> *ecx 0/r32/eax  # Slice-start
 7464         8a/copy-byte *eax 0/r32/AL
 7465         81 4/subop/and %eax 0xff/imm32
 7466         3d/compare-eax-and 0x2a/imm32/asterisk
 7467         {
 7468           75/jump-if-!= break/disp8
 7469           ff 0/subop/increment *ecx
 7470           ba/copy-to-edx 1/imm32/true
 7471         }
 7472         # assert(is-identifier?(name))
 7473         (is-identifier? %ecx)  # => eax
 7474         3d/compare-eax-and 0/imm32/false
 7475         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 7476         #
 7477         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 7478         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 7479         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 7480         #
 7481         e9/jump loop/disp32
 7482       }
 7483     }
 7484     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 7485 $parse-mu-stmt:define-outputs:
 7486     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 7487     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 7488     89/<- %edi 0/r32/eax
 7489     {
 7490 $parse-mu-stmt:define-outputs-loop:
 7491       # if (output == null) break
 7492       81 7/subop/compare %edi 0/imm32
 7493       74/jump-if-= break/disp8
 7494       #
 7495       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 7496                                                     # and must be in vars. This call will be a no-op, but safe.
 7497       # output = output->next
 7498       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 7499       89/<- %edi 0/r32/eax
 7500       #
 7501       eb/jump loop/disp8
 7502     }
 7503 $parse-mu-stmt:end:
 7504     # . reclaim locals
 7505     81 0/subop/add %esp 0x10/imm32
 7506     # . restore registers
 7507     5f/pop-to-edi
 7508     5b/pop-to-ebx
 7509     5a/pop-to-edx
 7510     59/pop-to-ecx
 7511     58/pop-to-eax
 7512     # . epilogue
 7513     89/<- %esp 5/r32/ebp
 7514     5d/pop-to-ebp
 7515     c3/return
 7516 
 7517 $parse-mu-stmt:abort:
 7518     # error("invalid identifier '" name "'\n")
 7519     (write-buffered *(ebp+0x18) "invalid identifier '")
 7520     (write-slice-buffered *(ebp+0x18) %ecx)
 7521     (write-buffered *(ebp+0x18) "'\n")
 7522     (flush *(ebp+0x18))
 7523     (stop *(ebp+0x1c) 1)
 7524     # never gets here
 7525 
 7526 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)
 7527     # pseudocode:
 7528     #   stmt->name = slice-to-string(next-mu-token(line))
 7529     #   while true
 7530     #     name = next-mu-token(line)
 7531     #     v = lookup-var-or-literal(name)
 7532     #     stmt->inouts = append(v, stmt->inouts)
 7533     #
 7534     # . prologue
 7535     55/push-ebp
 7536     89/<- %ebp 4/r32/esp
 7537     # . save registers
 7538     50/push-eax
 7539     51/push-ecx
 7540     52/push-edx
 7541     53/push-ebx
 7542     56/push-esi
 7543     57/push-edi
 7544     # edi = stmt
 7545     8b/-> *(ebp+8) 7/r32/edi
 7546     # var name/ecx: slice
 7547     68/push 0/imm32/end
 7548     68/push 0/imm32/start
 7549     89/<- %ecx 4/r32/esp
 7550     # var is-deref?/edx: boolean = false
 7551     ba/copy-to-edx 0/imm32/false
 7552     # var v/esi: (handle var)
 7553     68/push 0/imm32
 7554     68/push 0/imm32
 7555     89/<- %esi 4/r32/esp
 7556 $add-operation-and-inputs-to-stmt:read-operation:
 7557     (next-mu-token *(ebp+0xc) %ecx)
 7558     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 7559     (slice-to-string Heap %ecx %eax)
 7560     # var is-get?/ebx: boolean = (name == "get")
 7561     (slice-equal? %ecx "get")  # => eax
 7562     89/<- %ebx 0/r32/eax
 7563     {
 7564 $add-operation-and-inputs-to-stmt:read-inouts:
 7565       # name = next-mu-token(line)
 7566       (next-mu-token *(ebp+0xc) %ecx)
 7567       # if slice-empty?(word-slice) break
 7568       (slice-empty? %ecx)  # => eax
 7569       3d/compare-eax-and 0/imm32/false
 7570       0f 85/jump-if-!= break/disp32
 7571       # if (name == "<-") abort
 7572       (slice-equal? %ecx "<-")
 7573       3d/compare-eax-and 0/imm32/false
 7574       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 7575       # if (is-get? && second operand) lookup or create offset
 7576       {
 7577         81 7/subop/compare %ebx 0/imm32/false
 7578         74/jump-if-= break/disp8
 7579         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 7580         3d/compare-eax-and 0/imm32
 7581         74/jump-if-= break/disp8
 7582         (lookup-or-create-constant %eax %ecx %esi)
 7583 #?         (lookup *esi *(esi+4))
 7584 #?         (write-buffered Stderr "creating new output var ")
 7585 #?         (print-int32-buffered Stderr %eax)
 7586 #?         (write-buffered Stderr " for field called ")
 7587 #?         (write-slice-buffered Stderr %ecx)
 7588 #?         (write-buffered Stderr "; var name ")
 7589 #?         (lookup *eax *(eax+4))  # Var-name
 7590 #?         (write-buffered Stderr %eax)
 7591 #?         (write-buffered Stderr Newline)
 7592 #?         (flush Stderr)
 7593         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 7594       }
 7595       # is-deref? = false
 7596       ba/copy-to-edx 0/imm32/false
 7597       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 7598       8b/-> *ecx 0/r32/eax  # Slice-start
 7599       8a/copy-byte *eax 0/r32/AL
 7600       81 4/subop/and %eax 0xff/imm32
 7601       3d/compare-eax-and 0x2a/imm32/asterisk
 7602       {
 7603         75/jump-if-!= break/disp8
 7604 $add-operation-and-inputs-to-stmt:inout-is-deref:
 7605         ff 0/subop/increment *ecx
 7606         ba/copy-to-edx 1/imm32/true
 7607       }
 7608       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 7609 $add-operation-and-inputs-to-stmt:save-var:
 7610       8d/copy-address *(edi+0xc) 0/r32/eax
 7611       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 7612       #
 7613       e9/jump loop/disp32
 7614     }
 7615 $add-operation-and-inputs-to-stmt:end:
 7616     # . reclaim locals
 7617     81 0/subop/add %esp 0x10/imm32
 7618     # . restore registers
 7619     5f/pop-to-edi
 7620     5e/pop-to-esi
 7621     5b/pop-to-ebx
 7622     5a/pop-to-edx
 7623     59/pop-to-ecx
 7624     58/pop-to-eax
 7625     # . epilogue
 7626     89/<- %esp 5/r32/ebp
 7627     5d/pop-to-ebp
 7628     c3/return
 7629 
 7630 $add-operation-and-inputs-to-stmt:abort:
 7631     # error("fn ___: invalid identifier in '" line "'\n")
 7632     (write-buffered *(ebp+0x18) "fn ")
 7633     8b/-> *(ebp+0x14) 0/r32/eax
 7634     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7635     (write-buffered *(ebp+0x18) %eax)
 7636     (rewind-stream *(ebp+0xc))
 7637     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 7638     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 7639     (write-buffered *(ebp+0x18) "'\n")
 7640     (flush *(ebp+0x18))
 7641     (stop *(ebp+0x1c) 1)
 7642     # never gets here
 7643 
 7644 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 7645     # . prologue
 7646     55/push-ebp
 7647     89/<- %ebp 4/r32/esp
 7648     # . save registers
 7649     51/push-ecx
 7650     # var word-slice/ecx: slice
 7651     68/push 0/imm32/end
 7652     68/push 0/imm32/start
 7653     89/<- %ecx 4/r32/esp
 7654     # result = false
 7655     b8/copy-to-eax 0/imm32/false
 7656     (rewind-stream *(ebp+8))
 7657     {
 7658       (next-mu-token *(ebp+8) %ecx)
 7659       # if slice-empty?(word-slice) break
 7660       (slice-empty? %ecx)
 7661       3d/compare-eax-and 0/imm32/false
 7662       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 7663       0f 85/jump-if-!= break/disp32
 7664       # if slice-starts-with?(word-slice, '#') break
 7665       # . eax = *word-slice->start
 7666       8b/-> *ecx 0/r32/eax
 7667       8a/copy-byte *eax 0/r32/AL
 7668       81 4/subop/and %eax 0xff/imm32
 7669       # . if (eax == '#') break
 7670       3d/compare-eax-and 0x23/imm32/hash
 7671       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 7672       0f 84/jump-if-= break/disp32
 7673       # if slice-equal?(word-slice, '<-') return true
 7674       (slice-equal? %ecx "<-")
 7675       3d/compare-eax-and 0/imm32/false
 7676       74/jump-if-= loop/disp8
 7677       b8/copy-to-eax 1/imm32/true
 7678     }
 7679 $stmt-has-outputs:end:
 7680     (rewind-stream *(ebp+8))
 7681     # . reclaim locals
 7682     81 0/subop/add %esp 8/imm32
 7683     # . restore registers
 7684     59/pop-to-ecx
 7685     # . epilogue
 7686     89/<- %esp 5/r32/ebp
 7687     5d/pop-to-ebp
 7688     c3/return
 7689 
 7690 # if 'name' starts with a digit, create a new literal var for it
 7691 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 7692 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)
 7693     # . prologue
 7694     55/push-ebp
 7695     89/<- %ebp 4/r32/esp
 7696     # . save registers
 7697     50/push-eax
 7698     51/push-ecx
 7699     56/push-esi
 7700     # esi = name
 7701     8b/-> *(ebp+8) 6/r32/esi
 7702     # if slice-empty?(name) abort
 7703     (slice-empty? %esi)  # => eax
 7704     3d/compare-eax-and 0/imm32/false
 7705     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 7706     # var c/ecx: byte = *name->start
 7707     8b/-> *esi 1/r32/ecx
 7708     8a/copy-byte *ecx 1/r32/CL
 7709     81 4/subop/and %ecx 0xff/imm32
 7710     # if is-decimal-digit?(c) return new var(name)
 7711     {
 7712       (is-decimal-digit? %ecx)  # => eax
 7713       3d/compare-eax-and 0/imm32/false
 7714       74/jump-if-= break/disp8
 7715 $lookup-var-or-literal:literal:
 7716       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 7717       eb/jump $lookup-var-or-literal:end/disp8
 7718     }
 7719     # else if (c == '"') return new var(name)
 7720     {
 7721       81 7/subop/compare %ecx 0x22/imm32/dquote
 7722       75/jump-if-!= break/disp8
 7723 $lookup-var-or-literal:literal-string:
 7724       (new-literal Heap %esi *(ebp+0x10))
 7725       eb/jump $lookup-var-or-literal:end/disp8
 7726     }
 7727     # otherwise return lookup-var(name, vars)
 7728     {
 7729 $lookup-var-or-literal:var:
 7730       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 7731     }
 7732 $lookup-var-or-literal:end:
 7733     # . restore registers
 7734     5e/pop-to-esi
 7735     59/pop-to-ecx
 7736     58/pop-to-eax
 7737     # . epilogue
 7738     89/<- %esp 5/r32/ebp
 7739     5d/pop-to-ebp
 7740     c3/return
 7741 
 7742 $lookup-var-or-literal:abort:
 7743     (write-buffered *(ebp+0x18) "fn ")
 7744     8b/-> *(ebp+0x14) 0/r32/eax
 7745     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7746     (write-buffered *(ebp+0x18) %eax)
 7747     (write-buffered *(ebp+0x18) ": empty variable!")
 7748     (flush *(ebp+0x18))
 7749     (stop *(ebp+0x1c) 1)
 7750     # never gets here
 7751 
 7752 # return first 'name' from the top (back) of 'vars' and abort if not found
 7753 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)
 7754     # . prologue
 7755     55/push-ebp
 7756     89/<- %ebp 4/r32/esp
 7757     # . save registers
 7758     50/push-eax
 7759     #
 7760     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 7761     # if (*out == 0) abort
 7762     8b/-> *(ebp+0x10) 0/r32/eax
 7763     81 7/subop/compare *eax 0/imm32
 7764     74/jump-if-= $lookup-var:abort/disp8
 7765 $lookup-var:end:
 7766     # . restore registers
 7767     58/pop-to-eax
 7768     # . epilogue
 7769     89/<- %esp 5/r32/ebp
 7770     5d/pop-to-ebp
 7771     c3/return
 7772 
 7773 $lookup-var:abort:
 7774     (write-buffered *(ebp+0x18) "fn ")
 7775     8b/-> *(ebp+0x14) 0/r32/eax
 7776     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7777     (write-buffered *(ebp+0x18) %eax)
 7778     (write-buffered *(ebp+0x18) ": unknown variable '")
 7779     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 7780     (write-buffered *(ebp+0x18) "'\n")
 7781     (flush *(ebp+0x18))
 7782     (stop *(ebp+0x1c) 1)
 7783     # never gets here
 7784 
 7785 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 7786 # ensure that 'name' if in a register is the topmost variable in that register
 7787 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)
 7788     # pseudocode:
 7789     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 7790     #   var min = vars->data
 7791     #   while curr >= min
 7792     #     var v: (handle var) = *curr
 7793     #     if v->name == name
 7794     #       return
 7795     #     curr -= 12
 7796     #
 7797     # . prologue
 7798     55/push-ebp
 7799     89/<- %ebp 4/r32/esp
 7800     # . save registers
 7801     50/push-eax
 7802     51/push-ecx
 7803     52/push-edx
 7804     53/push-ebx
 7805     56/push-esi
 7806     57/push-edi
 7807     # clear out
 7808     (zero-out *(ebp+0x10) *Handle-size)
 7809     # esi = vars
 7810     8b/-> *(ebp+0xc) 6/r32/esi
 7811     # ebx = vars->top
 7812     8b/-> *esi 3/r32/ebx
 7813     # if (vars->top > vars->size) abort
 7814     3b/compare<- *(esi+4) 0/r32/eax
 7815     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 7816     # var min/edx: (addr handle var) = vars->data
 7817     8d/copy-address *(esi+8) 2/r32/edx
 7818     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 7819     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 7820     # var var-in-reg/edi: 8 addrs
 7821     68/push 0/imm32
 7822     68/push 0/imm32
 7823     68/push 0/imm32
 7824     68/push 0/imm32
 7825     68/push 0/imm32
 7826     68/push 0/imm32
 7827     68/push 0/imm32
 7828     68/push 0/imm32
 7829     89/<- %edi 4/r32/esp
 7830     {
 7831 $lookup-var-helper:loop:
 7832       # if (curr < min) return
 7833       39/compare %ebx 2/r32/edx
 7834       0f 82/jump-if-addr< break/disp32
 7835       # var v/ecx: (addr var) = lookup(*curr)
 7836       (lookup *ebx *(ebx+4))  # => eax
 7837       89/<- %ecx 0/r32/eax
 7838       # var vn/eax: (addr array byte) = lookup(v->name)
 7839       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 7840       # if (vn == name) return curr
 7841       (slice-equal? *(ebp+8) %eax)  # => eax
 7842       3d/compare-eax-and 0/imm32/false
 7843       {
 7844         74/jump-if-= break/disp8
 7845 $lookup-var-helper:found:
 7846         # var vr/eax: (addr array byte) = lookup(v->register)
 7847         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 7848         3d/compare-eax-and 0/imm32
 7849         {
 7850           74/jump-if-= break/disp8
 7851 $lookup-var-helper:found-register:
 7852           # var reg/eax: int = get(Registers, vr)
 7853           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 7854           8b/-> *eax 0/r32/eax
 7855           # if (var-in-reg[reg]) error
 7856           8b/-> *(edi+eax<<2) 0/r32/eax
 7857           3d/compare-eax-and 0/imm32
 7858           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 7859         }
 7860 $lookup-var-helper:return:
 7861         # esi = out
 7862         8b/-> *(ebp+0x10) 6/r32/esi
 7863         # *out = *curr
 7864         8b/-> *ebx 0/r32/eax
 7865         89/<- *esi 0/r32/eax
 7866         8b/-> *(ebx+4) 0/r32/eax
 7867         89/<- *(esi+4) 0/r32/eax
 7868         # return
 7869         eb/jump $lookup-var-helper:end/disp8
 7870       }
 7871       # 'name' not yet found; update var-in-reg if v in register
 7872       # . var vr/eax: (addr array byte) = lookup(v->register)
 7873       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 7874       # . if (var == 0) continue
 7875       3d/compare-eax-and 0/imm32
 7876       74/jump-if-= $lookup-var-helper:continue/disp8
 7877       # . var reg/eax: int = get(Registers, vr)
 7878       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 7879       8b/-> *eax 0/r32/eax
 7880       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 7881       81 7/subop/compare *(edi+eax<<2) 0/imm32
 7882       75/jump-if-!= $lookup-var-helper:continue/disp8
 7883       89/<- *(edi+eax<<2) 1/r32/ecx
 7884 $lookup-var-helper:continue:
 7885       # curr -= 12
 7886       81 5/subop/subtract %ebx 0xc/imm32
 7887       e9/jump loop/disp32
 7888     }
 7889 $lookup-var-helper:end:
 7890     # . reclaim locals
 7891     81 0/subop/add %esp 0x20/imm32
 7892     # . restore registers
 7893     5f/pop-to-edi
 7894     5e/pop-to-esi
 7895     5b/pop-to-ebx
 7896     5a/pop-to-edx
 7897     59/pop-to-ecx
 7898     58/pop-to-eax
 7899     # . epilogue
 7900     89/<- %esp 5/r32/ebp
 7901     5d/pop-to-ebp
 7902     c3/return
 7903 
 7904 $lookup-var-helper:error1:
 7905     (write-buffered *(ebp+0x18) "fn ")
 7906     8b/-> *(ebp+0x14) 0/r32/eax
 7907     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7908     (write-buffered *(ebp+0x18) %eax)
 7909     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 7910     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 7911     (write-buffered *(ebp+0x18) "'\n")
 7912     (flush *(ebp+0x18))
 7913     (stop *(ebp+0x1c) 1)
 7914     # never gets here
 7915 
 7916 $lookup-var-helper:error2:
 7917     # eax contains the conflicting var at this point
 7918     (write-buffered *(ebp+0x18) "fn ")
 7919     50/push-eax
 7920     8b/-> *(ebp+0x14) 0/r32/eax
 7921     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 7922     (write-buffered *(ebp+0x18) %eax)
 7923     58/pop-eax
 7924     (write-buffered *(ebp+0x18) ": register ")
 7925     50/push-eax
 7926     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 7927     (write-buffered *(ebp+0x18) %eax)
 7928     58/pop-to-eax
 7929     (write-buffered *(ebp+0x18) " reads var '")
 7930     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 7931     (write-buffered *(ebp+0x18) "' after writing var '")
 7932     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7933     (write-buffered *(ebp+0x18) %eax)
 7934     (write-buffered *(ebp+0x18) "'\n")
 7935     (flush *(ebp+0x18))
 7936     (stop *(ebp+0x1c) 1)
 7937     # never gets here
 7938 
 7939 dump-vars:  # vars: (addr stack live-var)
 7940     # pseudocode:
 7941     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 7942     #   var min = vars->data
 7943     #   while curr >= min
 7944     #     var v: (handle var) = *curr
 7945     #     print v
 7946     #     curr -= 12
 7947     #
 7948     # . prologue
 7949     55/push-ebp
 7950     89/<- %ebp 4/r32/esp
 7951     # . save registers
 7952     52/push-edx
 7953     53/push-ebx
 7954     56/push-esi
 7955     # esi = vars
 7956     8b/-> *(ebp+8) 6/r32/esi
 7957     # ebx = vars->top
 7958     8b/-> *esi 3/r32/ebx
 7959     # var min/edx: (addr handle var) = vars->data
 7960     8d/copy-address *(esi+8) 2/r32/edx
 7961     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 7962     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 7963     {
 7964 $dump-vars:loop:
 7965       # if (curr < min) return
 7966       39/compare %ebx 2/r32/edx
 7967       0f 82/jump-if-addr< break/disp32
 7968       #
 7969       (write-buffered Stderr "  var@")
 7970       (dump-var 2 %ebx)
 7971       # curr -= 12
 7972       81 5/subop/subtract %ebx 0xc/imm32
 7973       e9/jump loop/disp32
 7974     }
 7975 $dump-vars:end:
 7976     # . restore registers
 7977     5e/pop-to-esi
 7978     5b/pop-to-ebx
 7979     5a/pop-to-edx
 7980     # . epilogue
 7981     89/<- %esp 5/r32/ebp
 7982     5d/pop-to-ebp
 7983     c3/return
 7984 
 7985 == data
 7986 # Like Registers, but no esp or ebp
 7987 Mu-registers:  # (addr stream {(handle array byte), int})
 7988   # a table is a stream
 7989   0x48/imm32/write
 7990   0/imm32/read
 7991   0x48/imm32/length
 7992   # data
 7993   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 7994   0x11/imm32/alloc-id $Register-eax/imm32 0/imm32
 7995   0x11/imm32/alloc-id $Register-ecx/imm32 1/imm32
 7996   0x11/imm32/alloc-id $Register-edx/imm32 2/imm32
 7997   0x11/imm32/alloc-id $Register-ebx/imm32 3/imm32
 7998   0x11/imm32/alloc-id $Register-esi/imm32 6/imm32
 7999   0x11/imm32/alloc-id $Register-edi/imm32 7/imm32
 8000 
 8001 == code
 8002 
 8003 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 8004 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)
 8005     # . prologue
 8006     55/push-ebp
 8007     89/<- %ebp 4/r32/esp
 8008     # . save registers
 8009     50/push-eax
 8010     #
 8011     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 8012     {
 8013       # if (out != 0) return
 8014       8b/-> *(ebp+0x14) 0/r32/eax
 8015       81 7/subop/compare *eax 0/imm32
 8016       75/jump-if-!= break/disp8
 8017       # if name is one of fn's outputs, return it
 8018       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 8019       8b/-> *(ebp+0x14) 0/r32/eax
 8020       81 7/subop/compare *eax 0/imm32
 8021       # otherwise abort
 8022       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 8023     }
 8024 $lookup-or-define-var:end:
 8025     # . restore registers
 8026     58/pop-to-eax
 8027     # . epilogue
 8028     89/<- %esp 5/r32/ebp
 8029     5d/pop-to-ebp
 8030     c3/return
 8031 
 8032 $lookup-or-define-var:abort:
 8033     (write-buffered *(ebp+0x18) "unknown variable '")
 8034     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8035     (write-buffered *(ebp+0x18) "'\n")
 8036     (flush *(ebp+0x18))
 8037     (stop *(ebp+0x1c) 1)
 8038     # never gets here
 8039 
 8040 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 8041     # . prologue
 8042     55/push-ebp
 8043     89/<- %ebp 4/r32/esp
 8044     # . save registers
 8045     50/push-eax
 8046     51/push-ecx
 8047     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 8048     8b/-> *(ebp+8) 1/r32/ecx
 8049     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8050     89/<- %ecx 0/r32/eax
 8051     # while curr != null
 8052     {
 8053       81 7/subop/compare %ecx 0/imm32
 8054       74/jump-if-= break/disp8
 8055       # var v/eax: (addr var) = lookup(curr->value)
 8056       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 8057       # var s/eax: (addr array byte) = lookup(v->name)
 8058       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8059       # if (s == name) return curr->value
 8060       (slice-equal? *(ebp+0xc) %eax)  # => eax
 8061       3d/compare-eax-and 0/imm32/false
 8062       {
 8063         74/jump-if-= break/disp8
 8064         # var edi = out
 8065         57/push-edi
 8066         8b/-> *(ebp+0x10) 7/r32/edi
 8067         # *out = curr->value
 8068         8b/-> *ecx 0/r32/eax
 8069         89/<- *edi 0/r32/eax
 8070         8b/-> *(ecx+4) 0/r32/eax
 8071         89/<- *(edi+4) 0/r32/eax
 8072         #
 8073         5f/pop-to-edi
 8074         eb/jump $find-in-function-outputs:end/disp8
 8075       }
 8076       # curr = curr->next
 8077       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 8078       89/<- %ecx 0/r32/eax
 8079       #
 8080       eb/jump loop/disp8
 8081     }
 8082     b8/copy-to-eax 0/imm32
 8083 $find-in-function-outputs:end:
 8084     # . restore registers
 8085     59/pop-to-ecx
 8086     58/pop-to-eax
 8087     # . epilogue
 8088     89/<- %esp 5/r32/ebp
 8089     5d/pop-to-ebp
 8090     c3/return
 8091 
 8092 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 8093 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 8094     # . prologue
 8095     55/push-ebp
 8096     89/<- %ebp 4/r32/esp
 8097     # . save registers
 8098     50/push-eax
 8099     # var out-addr/eax: (addr var)
 8100     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 8101     #
 8102     (binding-exists? %eax *(ebp+0x10))  # => eax
 8103     3d/compare-eax-and 0/imm32/false
 8104     75/jump-if-!= $maybe-define-var:end/disp8
 8105     # otherwise update vars
 8106     (push *(ebp+0x10) *(ebp+8))
 8107     (push *(ebp+0x10) *(ebp+0xc))
 8108     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 8109 $maybe-define-var:end:
 8110     # . restore registers
 8111     58/pop-to-eax
 8112     # . epilogue
 8113     89/<- %esp 5/r32/ebp
 8114     5d/pop-to-ebp
 8115     c3/return
 8116 
 8117 # simpler version of lookup-var-helper
 8118 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 8119     # pseudocode:
 8120     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 8121     #   var min = vars->data
 8122     #   while curr >= min
 8123     #     var v: (handle var) = *curr
 8124     #     if v->name == target->name
 8125     #       return true
 8126     #     curr -= 12
 8127     #   return false
 8128     #
 8129     # . prologue
 8130     55/push-ebp
 8131     89/<- %ebp 4/r32/esp
 8132     # . save registers
 8133     51/push-ecx
 8134     52/push-edx
 8135     56/push-esi
 8136     # var target-name/ecx: (addr array byte) = lookup(target->name)
 8137     8b/-> *(ebp+8) 0/r32/eax
 8138     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8139     89/<- %ecx 0/r32/eax
 8140     # esi = vars
 8141     8b/-> *(ebp+0xc) 6/r32/esi
 8142     # eax = vars->top
 8143     8b/-> *esi 0/r32/eax
 8144     # var min/edx: (addr handle var) = vars->data
 8145     8d/copy-address *(esi+8) 2/r32/edx
 8146     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 8147     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 8148     {
 8149 $binding-exists?:loop:
 8150       # if (curr < min) return
 8151       39/compare %esi 2/r32/edx
 8152       0f 82/jump-if-addr< break/disp32
 8153       # var v/eax: (addr var) = lookup(*curr)
 8154       (lookup *esi *(esi+4))  # => eax
 8155       # var vn/eax: (addr array byte) = lookup(v->name)
 8156       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8157       # if (vn == target-name) return true
 8158       (string-equal? %ecx %eax)  # => eax
 8159       3d/compare-eax-and 0/imm32/false
 8160       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 8161       # curr -= 12
 8162       81 5/subop/subtract %esi 0xc/imm32
 8163       e9/jump loop/disp32
 8164     }
 8165     b8/copy-to-eax 0/imm32/false
 8166 $binding-exists?:end:
 8167     # . restore registers
 8168     5e/pop-to-esi
 8169     5a/pop-to-edx
 8170     59/pop-to-ecx
 8171     # . epilogue
 8172     89/<- %esp 5/r32/ebp
 8173     5d/pop-to-ebp
 8174     c3/return
 8175 
 8176 test-parse-mu-stmt:
 8177     # . prologue
 8178     55/push-ebp
 8179     89/<- %ebp 4/r32/esp
 8180     # setup
 8181     (clear-stream _test-input-stream)
 8182     (write _test-input-stream "increment n\n")
 8183     # var vars/ecx: (stack (addr var) 16)
 8184     81 5/subop/subtract %esp 0xc0/imm32
 8185     68/push 0xc0/imm32/size
 8186     68/push 0/imm32/top
 8187     89/<- %ecx 4/r32/esp
 8188     (clear-stack %ecx)
 8189     # var v/edx: (handle var)
 8190     68/push 0/imm32
 8191     68/push 0/imm32
 8192     89/<- %edx 4/r32/esp
 8193     # var s/eax: (handle array byte)
 8194     68/push 0/imm32
 8195     68/push 0/imm32
 8196     89/<- %eax 4/r32/esp
 8197     # v = new var("n")
 8198     (copy-array Heap "n" %eax)
 8199     (new-var Heap *eax *(eax+4) %edx)
 8200     #
 8201     (push %ecx *edx)
 8202     (push %ecx *(edx+4))
 8203     (push %ecx 0)
 8204     # var out/eax: (handle stmt)
 8205     68/push 0/imm32
 8206     68/push 0/imm32
 8207     89/<- %eax 4/r32/esp
 8208     # convert
 8209     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 8210     # var out-addr/edx: (addr stmt) = lookup(*out)
 8211     (lookup *eax *(eax+4))  # => eax
 8212     89/<- %edx 0/r32/eax
 8213     # out->tag
 8214     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 8215     # out->operation
 8216     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 8217     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 8218     # out->inouts->value->name
 8219     # . eax = out->inouts
 8220     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8221     # . eax = out->inouts->value
 8222     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8223     # . eax = out->inouts->value->name
 8224     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8225     # .
 8226     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 8227     # . epilogue
 8228     89/<- %esp 5/r32/ebp
 8229     5d/pop-to-ebp
 8230     c3/return
 8231 
 8232 test-parse-mu-stmt-with-comma:
 8233     # . prologue
 8234     55/push-ebp
 8235     89/<- %ebp 4/r32/esp
 8236     # setup
 8237     (clear-stream _test-input-stream)
 8238     (write _test-input-stream "copy-to n, 3\n")
 8239     # var vars/ecx: (stack (addr var) 16)
 8240     81 5/subop/subtract %esp 0xc0/imm32
 8241     68/push 0xc0/imm32/size
 8242     68/push 0/imm32/top
 8243     89/<- %ecx 4/r32/esp
 8244     (clear-stack %ecx)
 8245     # var v/edx: (handle var)
 8246     68/push 0/imm32
 8247     68/push 0/imm32
 8248     89/<- %edx 4/r32/esp
 8249     # var s/eax: (handle array byte)
 8250     68/push 0/imm32
 8251     68/push 0/imm32
 8252     89/<- %eax 4/r32/esp
 8253     # v = new var("n")
 8254     (copy-array Heap "n" %eax)
 8255     (new-var Heap *eax *(eax+4) %edx)
 8256     #
 8257     (push %ecx *edx)
 8258     (push %ecx *(edx+4))
 8259     (push %ecx 0)
 8260     # var out/eax: (handle stmt)
 8261     68/push 0/imm32
 8262     68/push 0/imm32
 8263     89/<- %eax 4/r32/esp
 8264     # convert
 8265     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 8266     # var out-addr/edx: (addr stmt) = lookup(*out)
 8267     (lookup *eax *(eax+4))  # => eax
 8268     89/<- %edx 0/r32/eax
 8269     # out->tag
 8270     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 8271     # out->operation
 8272     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 8273     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 8274     # out->inouts->value->name
 8275     # . eax = out->inouts
 8276     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8277     # . eax = out->inouts->value
 8278     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8279     # . eax = out->inouts->value->name
 8280     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8281     # .
 8282     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 8283     # . epilogue
 8284     89/<- %esp 5/r32/ebp
 8285     5d/pop-to-ebp
 8286     c3/return
 8287 
 8288 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 8289     # . prologue
 8290     55/push-ebp
 8291     89/<- %ebp 4/r32/esp
 8292     # . save registers
 8293     50/push-eax
 8294     51/push-ecx
 8295     # ecx = out
 8296     8b/-> *(ebp+0x14) 1/r32/ecx
 8297     #
 8298     (allocate *(ebp+8) *Var-size %ecx)
 8299     # var out-addr/eax: (addr var)
 8300     (lookup *ecx *(ecx+4))  # => eax
 8301     # out-addr->name = name
 8302     8b/-> *(ebp+0xc) 1/r32/ecx
 8303     89/<- *eax 1/r32/ecx  # Var-name
 8304     8b/-> *(ebp+0x10) 1/r32/ecx
 8305     89/<- *(eax+4) 1/r32/ecx  # Var-name
 8306 #?     (write-buffered Stderr "var ")
 8307 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 8308 #?     (write-buffered Stderr %eax)
 8309 #?     (write-buffered Stderr " at ")
 8310 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 8311 #?     (lookup *ecx *(ecx+4))  # => eax
 8312 #?     (print-int32-buffered Stderr %eax)
 8313 #?     (write-buffered Stderr Newline)
 8314 #?     (flush Stderr)
 8315 $new-var:end:
 8316     # . restore registers
 8317     59/pop-to-ecx
 8318     58/pop-to-eax
 8319     # . epilogue
 8320     89/<- %esp 5/r32/ebp
 8321     5d/pop-to-ebp
 8322     c3/return
 8323 
 8324 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)
 8325     # . prologue
 8326     55/push-ebp
 8327     89/<- %ebp 4/r32/esp
 8328     # . save registers
 8329     50/push-eax
 8330     51/push-ecx
 8331     # if (!is-hex-int?(name)) abort
 8332     (is-hex-int? *(ebp+0xc))  # => eax
 8333     3d/compare-eax-and 0/imm32/false
 8334     0f 84/jump-if-= $new-literal-integer:abort/disp32
 8335     # out = new var(s)
 8336     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 8337     # var out-addr/ecx: (addr var) = lookup(*out)
 8338     8b/-> *(ebp+0x10) 0/r32/eax
 8339     (lookup *eax *(eax+4))  # => eax
 8340     89/<- %ecx 0/r32/eax
 8341     # out-addr->block-depth = *Curr-block-depth
 8342     8b/-> *Curr-block-depth 0/r32/eax
 8343     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8344     # out-addr->type = new tree()
 8345     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 8346     (allocate *(ebp+8) *Tree-size %eax)
 8347     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8348     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 8349     # nothing else to do; default type is 'literal'
 8350 $new-literal-integer:end:
 8351     # . reclaim locals
 8352     81 0/subop/add %esp 8/imm32
 8353     # . restore registers
 8354     59/pop-to-ecx
 8355     58/pop-to-eax
 8356     # . epilogue
 8357     89/<- %esp 5/r32/ebp
 8358     5d/pop-to-ebp
 8359     c3/return
 8360 
 8361 $new-literal-integer:abort:
 8362     (write-buffered *(ebp+0x18) "fn ")
 8363     8b/-> *(ebp+0x14) 0/r32/eax
 8364     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8365     (write-buffered *(ebp+0x18) %eax)
 8366     (write-buffered *(ebp+0x18) ": variable cannot begin with a digit '")
 8367     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
 8368     (write-buffered *(ebp+0x18) "'\n")
 8369     (flush *(ebp+0x18))
 8370     (stop *(ebp+0x1c) 1)
 8371     # never gets here
 8372 
 8373 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 8374     # . prologue
 8375     55/push-ebp
 8376     89/<- %ebp 4/r32/esp
 8377     # . save registers
 8378     50/push-eax
 8379     51/push-ecx
 8380     # var s/ecx: (handle array byte)
 8381     68/push 0/imm32
 8382     68/push 0/imm32
 8383     89/<- %ecx 4/r32/esp
 8384     # s = slice-to-string(name)
 8385     (slice-to-string Heap *(ebp+0xc) %ecx)
 8386     # allocate to out
 8387     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 8388     # var out-addr/ecx: (addr var) = lookup(*out)
 8389     8b/-> *(ebp+0x10) 1/r32/ecx
 8390     (lookup *ecx *(ecx+4))  # => eax
 8391     89/<- %ecx 0/r32/eax
 8392     # out-addr->block-depth = *Curr-block-depth
 8393     8b/-> *Curr-block-depth 0/r32/eax
 8394     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8395     # out-addr->type/eax = new type
 8396     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 8397     (allocate *(ebp+8) *Tree-size %eax)
 8398     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8399     # nothing else to do; default type is 'literal'
 8400     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 8401 $new-literal:end:
 8402     # . reclaim locals
 8403     81 0/subop/add %esp 8/imm32
 8404     # . restore registers
 8405     59/pop-to-ecx
 8406     58/pop-to-eax
 8407     # . epilogue
 8408     89/<- %esp 5/r32/ebp
 8409     5d/pop-to-ebp
 8410     c3/return
 8411 
 8412 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 8413     # . prologue
 8414     55/push-ebp
 8415     89/<- %ebp 4/r32/esp
 8416     # . save registers
 8417     51/push-ecx
 8418     # var tmp/ecx: (handle array byte)
 8419     68/push 0/imm32
 8420     68/push 0/imm32
 8421     89/<- %ecx 4/r32/esp
 8422     # tmp = slice-to-string(name)
 8423     (slice-to-string Heap *(ebp+0xc) %ecx)
 8424     # out = new-var(tmp)
 8425     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 8426 $new-var-from-slice:end:
 8427     # . reclaim locals
 8428     81 0/subop/add %esp 8/imm32
 8429     # . restore registers
 8430     59/pop-to-ecx
 8431     # . epilogue
 8432     89/<- %esp 5/r32/ebp
 8433     5d/pop-to-ebp
 8434     c3/return
 8435 
 8436 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 8437     # . prologue
 8438     55/push-ebp
 8439     89/<- %ebp 4/r32/esp
 8440     # . save registers
 8441     50/push-eax
 8442     51/push-ecx
 8443     #
 8444     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 8445     # var out-addr/eax: (addr stmt) = lookup(*out)
 8446     8b/-> *(ebp+0x14) 0/r32/eax
 8447     (lookup *eax *(eax+4))  # => eax
 8448     # out-addr->tag = stmt
 8449     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 8450     # result->var = var
 8451     8b/-> *(ebp+0xc) 1/r32/ecx
 8452     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 8453     8b/-> *(ebp+0x10) 1/r32/ecx
 8454     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 8455 $new-var-def:end:
 8456     # . restore registers
 8457     59/pop-to-ecx
 8458     58/pop-to-eax
 8459     # . epilogue
 8460     89/<- %esp 5/r32/ebp
 8461     5d/pop-to-ebp
 8462     c3/return
 8463 
 8464 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 8465     # . prologue
 8466     55/push-ebp
 8467     89/<- %ebp 4/r32/esp
 8468     # . save registers
 8469     50/push-eax
 8470     # eax = out
 8471     8b/-> *(ebp+0x14) 0/r32/eax
 8472     #
 8473     (allocate *(ebp+8) *Stmt-size %eax)
 8474     # var out-addr/eax: (addr stmt) = lookup(*out)
 8475     (lookup *eax *(eax+4))  # => eax
 8476     # set tag
 8477     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 8478     # set output
 8479     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 8480     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 8481 $new-reg-var-def:end:
 8482     # . restore registers
 8483     58/pop-to-eax
 8484     # . epilogue
 8485     89/<- %esp 5/r32/ebp
 8486     5d/pop-to-ebp
 8487     c3/return
 8488 
 8489 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 8490     # . prologue
 8491     55/push-ebp
 8492     89/<- %ebp 4/r32/esp
 8493     # . save registers
 8494     50/push-eax
 8495     51/push-ecx
 8496     57/push-edi
 8497     # edi = out
 8498     8b/-> *(ebp+0x1c) 7/r32/edi
 8499     # *out = new list
 8500     (allocate *(ebp+8) *List-size %edi)
 8501     # var out-addr/edi: (addr list _type) = lookup(*out)
 8502     (lookup *edi *(edi+4))  # => eax
 8503     89/<- %edi 0/r32/eax
 8504     # out-addr->value = value
 8505     8b/-> *(ebp+0xc) 0/r32/eax
 8506     89/<- *edi 0/r32/eax  # List-value
 8507     8b/-> *(ebp+0x10) 0/r32/eax
 8508     89/<- *(edi+4) 0/r32/eax  # List-value
 8509     # if (list == null) return
 8510     81 7/subop/compare *(ebp+0x14) 0/imm32
 8511     74/jump-if-= $append-list:end/disp8
 8512     # otherwise append
 8513 $append-list:non-empty-list:
 8514     # var curr/eax: (addr list _type) = lookup(list)
 8515     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 8516     # while (curr->next != null) curr = curr->next
 8517     {
 8518       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 8519       74/jump-if-= break/disp8
 8520       # curr = lookup(curr->next)
 8521       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 8522       #
 8523       eb/jump loop/disp8
 8524     }
 8525     # edi = out
 8526     8b/-> *(ebp+0x1c) 7/r32/edi
 8527     # curr->next = out
 8528     8b/-> *edi 1/r32/ecx
 8529     89/<- *(eax+8) 1/r32/ecx  # List-next
 8530     8b/-> *(edi+4) 1/r32/ecx
 8531     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 8532     # out = list
 8533     8b/-> *(ebp+0x14) 1/r32/ecx
 8534     89/<- *edi 1/r32/ecx
 8535     8b/-> *(ebp+0x18) 1/r32/ecx
 8536     89/<- *(edi+4) 1/r32/ecx
 8537 $append-list:end:
 8538     # . restore registers
 8539     5f/pop-to-edi
 8540     59/pop-to-ecx
 8541     58/pop-to-eax
 8542     # . epilogue
 8543     89/<- %esp 5/r32/ebp
 8544     5d/pop-to-ebp
 8545     c3/return
 8546 
 8547 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 8548     # . prologue
 8549     55/push-ebp
 8550     89/<- %ebp 4/r32/esp
 8551     # . save registers
 8552     50/push-eax
 8553     51/push-ecx
 8554     57/push-edi
 8555     # edi = out
 8556     8b/-> *(ebp+0x20) 7/r32/edi
 8557     # out = new stmt-var
 8558     (allocate *(ebp+8) *Stmt-var-size %edi)
 8559     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 8560     (lookup *edi *(edi+4))  # => eax
 8561     89/<- %ecx 0/r32/eax
 8562     # out-addr->value = v
 8563     8b/-> *(ebp+0xc) 0/r32/eax
 8564     89/<- *ecx 0/r32/eax  # Stmt-var-value
 8565     8b/-> *(ebp+0x10) 0/r32/eax
 8566     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 8567     # out-addr->is-deref? = is-deref?
 8568     8b/-> *(ebp+0x1c) 0/r32/eax
 8569     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 8570     # if (vars == null) return result
 8571     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 8572     74/jump-if-= $append-stmt-var:end/disp8
 8573     # otherwise append
 8574     # var curr/eax: (addr stmt-var) = lookup(vars)
 8575     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 8576     # while (curr->next != null) curr = curr->next
 8577     {
 8578       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 8579       74/jump-if-= break/disp8
 8580       # curr = lookup(curr->next)
 8581       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 8582       #
 8583       eb/jump loop/disp8
 8584     }
 8585     # curr->next = out
 8586     8b/-> *edi 1/r32/ecx
 8587     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 8588     8b/-> *(edi+4) 1/r32/ecx
 8589     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 8590     # out = vars
 8591     8b/-> *(ebp+0x14) 1/r32/ecx
 8592     89/<- *edi 1/r32/ecx
 8593     8b/-> *(ebp+0x18) 1/r32/ecx
 8594     89/<- *(edi+4) 1/r32/ecx
 8595 $append-stmt-var:end:
 8596     # . restore registers
 8597     5f/pop-to-edi
 8598     59/pop-to-ecx
 8599     58/pop-to-eax
 8600     # . epilogue
 8601     89/<- %esp 5/r32/ebp
 8602     5d/pop-to-ebp
 8603     c3/return
 8604 
 8605 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 8606     # . prologue
 8607     55/push-ebp
 8608     89/<- %ebp 4/r32/esp
 8609     # . save registers
 8610     50/push-eax
 8611     56/push-esi
 8612     # esi = block
 8613     8b/-> *(ebp+0xc) 6/r32/esi
 8614     # block->stmts = append(x, block->stmts)
 8615     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 8616     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 8617 $append-to-block:end:
 8618     # . restore registers
 8619     5e/pop-to-esi
 8620     58/pop-to-eax
 8621     # . epilogue
 8622     89/<- %esp 5/r32/ebp
 8623     5d/pop-to-ebp
 8624     c3/return
 8625 
 8626 ## Parsing types
 8627 # We need to create metadata on user-defined types, and we need to use this
 8628 # metadata as we parse instructions.
 8629 # However, we also want to allow types to be used before their definitions.
 8630 # This means we can't ever assume any type data structures exist.
 8631 
 8632 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 8633     # . prologue
 8634     55/push-ebp
 8635     89/<- %ebp 4/r32/esp
 8636     # . save registers
 8637     50/push-eax
 8638     56/push-esi
 8639     # var container-type/esi: type-id
 8640     (container-type *(ebp+8))  # => eax
 8641     89/<- %esi 0/r32/eax
 8642     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 8643     68/push 0/imm32
 8644     68/push 0/imm32
 8645     89/<- %eax 4/r32/esp
 8646     (find-or-create-typeinfo %esi %eax)
 8647     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 8648     (lookup *eax *(eax+4))  # => eax
 8649     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 8650 #?     (write-buffered Stderr "constant: ")
 8651 #?     (write-slice-buffered Stderr *(ebp+0xc))
 8652 #?     (write-buffered Stderr Newline)
 8653 #?     (flush Stderr)
 8654     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 8655 #?     8b/-> *(ebp+0x10) 0/r32/eax
 8656 #?     (write-buffered Stderr "@")
 8657 #?     (lookup *eax *(eax+4))
 8658 #?     (print-int32-buffered Stderr %eax)
 8659 #?     (lookup *eax *(eax+4))
 8660 #?     (write-buffered Stderr %eax)
 8661 #?     (write-buffered Stderr Newline)
 8662 #?     (flush Stderr)
 8663 #?     (write-buffered Stderr "offset: ")
 8664 #?     8b/-> *(eax+0x14) 0/r32/eax
 8665 #?     (print-int32-buffered Stderr %eax)
 8666 #?     (write-buffered Stderr Newline)
 8667 #?     (flush Stderr)
 8668 $lookup-or-create-constant:end:
 8669     # . reclaim locals
 8670     81 0/subop/add %esp 8/imm32
 8671     # . restore registers
 8672     5e/pop-to-esi
 8673     58/pop-to-eax
 8674     # . epilogue
 8675     89/<- %esp 5/r32/ebp
 8676     5d/pop-to-ebp
 8677     c3/return
 8678 
 8679 # if addr var:
 8680 #   container->var->type->right->left->value
 8681 # otherwise
 8682 #   container->var->type->value
 8683 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 8684     # . prologue
 8685     55/push-ebp
 8686     89/<- %ebp 4/r32/esp
 8687     #
 8688     8b/-> *(ebp+8) 0/r32/eax
 8689     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8690     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 8691     {
 8692       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 8693       74/jump-if-= break/disp8
 8694       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 8695       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 8696     }
 8697     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 8698 $container-type:end:
 8699     # . epilogue
 8700     89/<- %esp 5/r32/ebp
 8701     5d/pop-to-ebp
 8702     c3/return
 8703 
 8704 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 8705     # . prologue
 8706     55/push-ebp
 8707     89/<- %ebp 4/r32/esp
 8708     # . save registers
 8709     50/push-eax
 8710     51/push-ecx
 8711     52/push-edx
 8712     57/push-edi
 8713     # edi = out
 8714     8b/-> *(ebp+0xc) 7/r32/edi
 8715     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 8716     68/push 0/imm32
 8717     68/push 0/imm32
 8718     89/<- %ecx 4/r32/esp
 8719     # find-typeinfo(t, out)
 8720     (find-typeinfo *(ebp+8) %edi)
 8721     {
 8722       # if (*out != 0) break
 8723       81 7/subop/compare *edi 0/imm32
 8724       0f 85/jump-if-!= break/disp32
 8725 $find-or-create-typeinfo:create:
 8726       # *out = allocate
 8727       (allocate Heap *Typeinfo-size %edi)
 8728       # var tmp/eax: (addr typeinfo) = lookup(*out)
 8729       (lookup *edi *(edi+4))  # => eax
 8730 #?     (write-buffered Stderr "created typeinfo at ")
 8731 #?     (print-int32-buffered Stderr %eax)
 8732 #?     (write-buffered Stderr " for type-id ")
 8733 #?     (print-int32-buffered Stderr *(ebp+8))
 8734 #?     (write-buffered Stderr Newline)
 8735 #?     (flush Stderr)
 8736       # tmp->id = t
 8737       8b/-> *(ebp+8) 2/r32/edx
 8738       89/<- *eax 2/r32/edx  # Typeinfo-id
 8739       # tmp->fields = new table
 8740       # . fields = new table
 8741       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 8742       # . tmp->fields = fields
 8743       8b/-> *ecx 2/r32/edx
 8744       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 8745       8b/-> *(ecx+4) 2/r32/edx
 8746       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 8747       # tmp->next = Program->types
 8748       8b/-> *_Program-types 1/r32/ecx
 8749       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 8750       8b/-> *_Program-types->payload 1/r32/ecx
 8751       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 8752       # Program->types = out
 8753       8b/-> *edi 1/r32/ecx
 8754       89/<- *_Program-types 1/r32/ecx
 8755       8b/-> *(edi+4) 1/r32/ecx
 8756       89/<- *_Program-types->payload 1/r32/ecx
 8757     }
 8758 $find-or-create-typeinfo:end:
 8759     # . reclaim locals
 8760     81 0/subop/add %esp 8/imm32
 8761     # . restore registers
 8762     5f/pop-to-edi
 8763     5a/pop-to-edx
 8764     59/pop-to-ecx
 8765     58/pop-to-eax
 8766     # . epilogue
 8767     89/<- %esp 5/r32/ebp
 8768     5d/pop-to-ebp
 8769     c3/return
 8770 
 8771 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 8772     # . prologue
 8773     55/push-ebp
 8774     89/<- %ebp 4/r32/esp
 8775     # . save registers
 8776     50/push-eax
 8777     51/push-ecx
 8778     52/push-edx
 8779     57/push-edi
 8780     # ecx = t
 8781     8b/-> *(ebp+8) 1/r32/ecx
 8782     # edi = out
 8783     8b/-> *(ebp+0xc) 7/r32/edi
 8784     # *out = Program->types
 8785     8b/-> *_Program-types 0/r32/eax
 8786     89/<- *edi 0/r32/eax
 8787     8b/-> *_Program-types->payload 0/r32/eax
 8788     89/<- *(edi+4) 0/r32/eax
 8789     {
 8790       # if (*out == 0) break
 8791       81 7/subop/compare *edi 0/imm32
 8792       74/jump-if-= break/disp8
 8793       # var tmp/eax: (addr typeinfo) = lookup(*out)
 8794       (lookup *edi *(edi+4))  # => eax
 8795       # if (tmp->id == t) break
 8796       39/compare *eax 1/r32/ecx  # Typeinfo-id
 8797       74/jump-if-= break/disp8
 8798       # *out = tmp->next
 8799       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 8800       89/<- *edi 2/r32/edx
 8801       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 8802       89/<- *(edi+4) 2/r32/edx
 8803       #
 8804       eb/jump loop/disp8
 8805     }
 8806 $find-typeinfo:end:
 8807     # . restore registers
 8808     5f/pop-to-edi
 8809     5a/pop-to-edx
 8810     59/pop-to-ecx
 8811     58/pop-to-eax
 8812     # . epilogue
 8813     89/<- %esp 5/r32/ebp
 8814     5d/pop-to-ebp
 8815     c3/return
 8816 
 8817 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 8818     # . prologue
 8819     55/push-ebp
 8820     89/<- %ebp 4/r32/esp
 8821     # . save registers
 8822     50/push-eax
 8823     52/push-edx
 8824     57/push-edi
 8825     # var dest/edi: (handle typeinfo-entry)
 8826     68/push 0/imm32
 8827     68/push 0/imm32
 8828     89/<- %edi 4/r32/esp
 8829     # find-or-create-typeinfo-fields(T, f, dest)
 8830     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 8831     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 8832     (lookup *edi *(edi+4))  # => eax
 8833     89/<- %edi 0/r32/eax
 8834     # if dest-addr->output-var doesn't exist, create it
 8835     {
 8836       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 8837       0f 85/jump-if-!= break/disp32
 8838       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 8839       # . var name/eax: (handle array byte) = "field"
 8840       68/push 0/imm32
 8841       68/push 0/imm32
 8842       89/<- %eax 4/r32/esp
 8843       (copy-array Heap "field" %eax)
 8844       # . new var
 8845       8d/copy-address *(edi+0xc) 2/r32/edx
 8846       (new-var Heap  *eax *(eax+4)  %edx)
 8847       # . reclaim name
 8848       81 0/subop/add %esp 8/imm32
 8849       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 8850       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 8851       89/<- %edx 0/r32/eax
 8852       # result->type = new constant type
 8853       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 8854       (allocate Heap *Tree-size %eax)
 8855       (lookup *(edx+8) *(edx+0xc))  # => eax
 8856       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 8857       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 8858       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 8859       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 8860       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 8861       # result->offset isn't filled out yet
 8862       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 8863     }
 8864     # out = dest-addr->output-var
 8865     8b/-> *(ebp+0x10) 2/r32/edx
 8866     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 8867     89/<- *edx 0/r32/eax
 8868     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 8869     89/<- *(edx+4) 0/r32/eax
 8870 $find-or-create-typeinfo-output-var:end:
 8871     # . reclaim locals
 8872     81 0/subop/add %esp 8/imm32
 8873     # . restore registers
 8874     5f/pop-to-edi
 8875     5a/pop-to-edx
 8876     58/pop-to-eax
 8877     # . epilogue
 8878     89/<- %esp 5/r32/ebp
 8879     5d/pop-to-ebp
 8880     c3/return
 8881 
 8882 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 8883     # . prologue
 8884     55/push-ebp
 8885     89/<- %ebp 4/r32/esp
 8886     # . save registers
 8887     50/push-eax
 8888     56/push-esi
 8889     57/push-edi
 8890     # eax = lookup(T->fields)
 8891     8b/-> *(ebp+8) 0/r32/eax
 8892     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 8893     # edi = out
 8894     8b/-> *(ebp+0x10) 7/r32/edi
 8895     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 8896     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 8897     89/<- %esi 0/r32/eax
 8898     # if src doesn't exist, allocate it
 8899     {
 8900       81 7/subop/compare *esi 0/imm32
 8901       75/jump-if-!= break/disp8
 8902       (allocate Heap *Typeinfo-entry-size %esi)
 8903 #?       (write-buffered Stderr "handle at ")
 8904 #?       (print-int32-buffered Stderr %esi)
 8905 #?       (write-buffered Stderr ": ")
 8906 #?       (print-int32-buffered Stderr *esi)
 8907 #?       (write-buffered Stderr " ")
 8908 #?       (print-int32-buffered Stderr *(esi+4))
 8909 #?       (write-buffered Stderr Newline)
 8910 #?       (flush Stderr)
 8911 #?       (lookup *esi *(esi+4))
 8912 #?       (write-buffered Stderr "created typeinfo fields at ")
 8913 #?       (print-int32-buffered Stderr %esi)
 8914 #?       (write-buffered Stderr " for ")
 8915 #?       (print-int32-buffered Stderr *(ebp+8))
 8916 #?       (write-buffered Stderr Newline)
 8917 #?       (flush Stderr)
 8918     }
 8919     # *out = src
 8920     # . *edi = *src
 8921     8b/-> *esi 0/r32/eax
 8922     89/<- *edi 0/r32/eax
 8923     8b/-> *(esi+4) 0/r32/eax
 8924     89/<- *(edi+4) 0/r32/eax
 8925 $find-or-create-typeinfo-fields:end:
 8926     # . restore registers
 8927     5f/pop-to-edi
 8928     5e/pop-to-esi
 8929     58/pop-to-eax
 8930     # . epilogue
 8931     89/<- %esp 5/r32/ebp
 8932     5d/pop-to-ebp
 8933     c3/return
 8934 
 8935 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 8936     # pseudocode:
 8937     #   var line: (stream byte 512)
 8938     #   curr-index = 0
 8939     #   while true
 8940     #     clear-stream(line)
 8941     #     read-line-buffered(in, line)
 8942     #     if line->write == 0
 8943     #       abort
 8944     #     word-slice = next-mu-token(line)
 8945     #     if slice-empty?(word-slice)               # end of line
 8946     #       continue
 8947     #     if slice-equal?(word-slice, "}")
 8948     #       break
 8949     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 8950     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 8951     #     TODO: ensure that r->first is null
 8952     #     r->index = curr-index
 8953     #     curr-index++
 8954     #     r->input-var = v
 8955     #     if r->output-var == 0
 8956     #       r->output-var = new literal
 8957     #     TODO: ensure nothing else in line
 8958     # t->total-size-in-bytes = -2 (not yet initialized)
 8959     # check-input-vars(t, err, ed)
 8960     #
 8961     # . prologue
 8962     55/push-ebp
 8963     89/<- %ebp 4/r32/esp
 8964     # var curr-index: int at *(ebp-4)
 8965     68/push 0/imm32
 8966     # . save registers
 8967     50/push-eax
 8968     51/push-ecx
 8969     52/push-edx
 8970     53/push-ebx
 8971     56/push-esi
 8972     57/push-edi
 8973     # edi = t
 8974     8b/-> *(ebp+0xc) 7/r32/edi
 8975     # var line/ecx: (stream byte 512)
 8976     81 5/subop/subtract %esp 0x200/imm32
 8977     68/push 0x200/imm32/size
 8978     68/push 0/imm32/read
 8979     68/push 0/imm32/write
 8980     89/<- %ecx 4/r32/esp
 8981     # var word-slice/edx: slice
 8982     68/push 0/imm32/end
 8983     68/push 0/imm32/start
 8984     89/<- %edx 4/r32/esp
 8985     # var v/esi: (handle var)
 8986     68/push 0/imm32
 8987     68/push 0/imm32
 8988     89/<- %esi 4/r32/esp
 8989     # var r/ebx: (handle typeinfo-entry)
 8990     68/push 0/imm32
 8991     68/push 0/imm32
 8992     89/<- %ebx 4/r32/esp
 8993     {
 8994 $populate-mu-type:line-loop:
 8995       (clear-stream %ecx)
 8996       (read-line-buffered *(ebp+8) %ecx)
 8997       # if (line->write == 0) abort
 8998       81 7/subop/compare *ecx 0/imm32
 8999       0f 84/jump-if-= $populate-mu-type:abort/disp32
 9000 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 9006       (next-mu-token %ecx %edx)
 9007       # if slice-empty?(word-slice) continue
 9008       (slice-empty? %edx)  # => eax
 9009       3d/compare-eax-and 0/imm32
 9010       0f 85/jump-if-!= loop/disp32
 9011       # if slice-equal?(word-slice, "}") break
 9012       (slice-equal? %edx "}")
 9013       3d/compare-eax-and 0/imm32
 9014       0f 85/jump-if-!= break/disp32
 9015 $populate-mu-type:parse-element:
 9016       # v = parse-var-with-type(word-slice, first-line)
 9017       # must do this first to strip the trailing ':' from word-slice before
 9018       # using it in find-or-create-typeinfo-fields below
 9019       # TODO: clean up that mutation in parse-var-with-type
 9020       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
 9021       # var tmp/ecx
 9022       51/push-ecx
 9023 $populate-mu-type:create-typeinfo-fields:
 9024       # var r/ebx: (handle typeinfo-entry)
 9025       (find-or-create-typeinfo-fields %edi %edx %ebx)
 9026       # r->index = curr-index
 9027       (lookup *ebx *(ebx+4))  # => eax
 9028       8b/-> *(ebp-4) 1/r32/ecx
 9029 #?       (write-buffered Stderr "saving index ")
 9030 #?       (print-int32-buffered Stderr %ecx)
 9031 #?       (write-buffered Stderr " at ")
 9032 #?       (print-int32-buffered Stderr %edi)
 9033 #?       (write-buffered Stderr Newline)
 9034 #?       (flush Stderr)
 9035       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 9036       # ++curr-index
 9037       ff 0/subop/increment *(ebp-4)
 9038 $populate-mu-type:set-input-type:
 9039       # r->input-var = v
 9040       8b/-> *esi 1/r32/ecx
 9041       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 9042       8b/-> *(esi+4) 1/r32/ecx
 9043       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 9044       59/pop-to-ecx
 9045       {
 9046 $populate-mu-type:create-output-type:
 9047         # if (r->output-var == 0) create a new var with some placeholder data
 9048         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 9049         75/jump-if-!= break/disp8
 9050         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 9051         (new-literal Heap %edx %eax)
 9052       }
 9053       e9/jump loop/disp32
 9054     }
 9055 $populate-mu-type:invalidate-total-size-in-bytes:
 9056     # Offsets and total size may not be accurate here since we may not yet
 9057     # have encountered the element types.
 9058     # We'll recompute them separately after parsing the entire program.
 9059     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 9060 $populate-mu-type:validate:
 9061     (check-input-vars *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9062 $populate-mu-type:end:
 9063     # . reclaim locals
 9064     81 0/subop/add %esp 0x224/imm32
 9065     # . restore registers
 9066     5f/pop-to-edi
 9067     5e/pop-to-esi
 9068     5b/pop-to-ebx
 9069     5a/pop-to-edx
 9070     59/pop-to-ecx
 9071     58/pop-to-eax
 9072     # reclaim curr-index
 9073     81 0/subop/add %esp 4/imm32
 9074     # . epilogue
 9075     89/<- %esp 5/r32/ebp
 9076     5d/pop-to-ebp
 9077     c3/return
 9078 
 9079 $populate-mu-type:abort:
 9080     # error("unexpected top-level command: " word-slice "\n")
 9081     (write-buffered *(ebp+0x10) "incomplete type definition '")
 9082     (type-name *edi)  # Typeinfo-id => eax
 9083     (write-buffered *(ebp+0x10) %eax)
 9084     (write-buffered *(ebp+0x10) "\n")
 9085     (flush *(ebp+0x10))
 9086     (stop *(ebp+0x14) 1)
 9087     # never gets here
 9088 
 9089 check-input-vars:  # t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 9090     # . prologue
 9091     55/push-ebp
 9092     89/<- %ebp 4/r32/esp
 9093     # . save registers
 9094     50/push-eax
 9095     51/push-ecx
 9096     52/push-edx
 9097     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(t->fields)
 9098     8b/-> *(ebp+8) 0/r32/eax
 9099     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 9100     89/<- %ecx 0/r32/eax
 9101     # var table-size/edx: int = table->write
 9102     8b/-> *ecx 2/r32/edx  # stream-write
 9103     # var curr/ecx: (addr table_row) = table->data
 9104     8d/copy-address *(ecx+0xc) 1/r32/ecx
 9105     # var max/edx: (addr table_row) = table->data + table->write
 9106     8d/copy-address *(ecx+edx) 2/r32/edx
 9107     {
 9108 $check-input-vars:loop:
 9109       # if (curr >= max) break
 9110       39/compare %ecx 2/r32/edx
 9111       73/jump-if-addr>= break/disp8
 9112       (lookup *ecx *(ecx+4))  # => eax
 9113       # var t2/eax: (addr typeinfo-entry) = lookup(curr->value)
 9114       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 9115       # if (t2->input-var == null) raise an error
 9116       8b/-> *eax 0/r32/eax  # Typeinfo-entry-input-var
 9117       3d/compare-eax-and 0/imm32/null
 9118       0f 84/jump-if-= $check-input-vars:abort/disp32
 9119       # curr += row-size
 9120       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 9121       #
 9122       eb/jump loop/disp8
 9123     }
 9124 $check-input-vars:end:
 9125     # . restore registers
 9126     5a/pop-to-edx
 9127     59/pop-to-ecx
 9128     58/pop-to-eax
 9129     # . epilogue
 9130     89/<- %esp 5/r32/ebp
 9131     5d/pop-to-ebp
 9132     c3/return
 9133 
 9134 $check-input-vars:abort:
 9135     # error("type " type " has no member called '" curr->name "'\n")
 9136     (write-buffered *(ebp+0xc) "type '")
 9137     # . var tmp/edx: int = t->id << 2
 9138     8b/-> *(ebp+8) 0/r32/eax
 9139     8b/-> *eax 2/r32/edx  # Typeinfo-id
 9140     c1/shift 4/subop/left %edx 2/imm8
 9141     # . var a/edx: (addr array byte) = Type-id->data[tmp]
 9142     b8/copy-to-eax Type-id/imm32
 9143     8b/-> *(eax+edx+0xc) 2/r32/edx
 9144     (write-buffered *(ebp+0xc) %edx)
 9145     (write-buffered *(ebp+0xc) "' has no member called '")
 9146     (lookup *ecx *(ecx+4))  # => eax
 9147     (write-buffered *(ebp+0xc) %eax)
 9148     (write-buffered *(ebp+0xc) "'\n")
 9149     (flush *(ebp+0xc))
 9150     (stop *(ebp+0x10) 1)
 9151     # never gets here
 9152 
 9153 type-name:  # index: int -> result/eax: (addr array byte)
 9154     # . prologue
 9155     55/push-ebp
 9156     89/<- %ebp 4/r32/esp
 9157     #
 9158     (index Type-id *(ebp+8))
 9159 $type-name:end:
 9160     # . epilogue
 9161     89/<- %esp 5/r32/ebp
 9162     5d/pop-to-ebp
 9163     c3/return
 9164 
 9165 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 9166     # . prologue
 9167     55/push-ebp
 9168     89/<- %ebp 4/r32/esp
 9169     # . save registers
 9170     56/push-esi
 9171     # TODO: bounds-check index
 9172     # esi = arr
 9173     8b/-> *(ebp+8) 6/r32/esi
 9174     # eax = index
 9175     8b/-> *(ebp+0xc) 0/r32/eax
 9176     # eax = *(arr + 12 + index)
 9177     8b/-> *(esi+eax+0xc) 0/r32/eax
 9178 $index:end:
 9179     # . restore registers
 9180     5e/pop-to-esi
 9181     # . epilogue
 9182     89/<- %esp 5/r32/ebp
 9183     5d/pop-to-ebp
 9184     c3/return
 9185 
 9186 #######################################################
 9187 # Compute type sizes
 9188 #######################################################
 9189 
 9190 # Compute the sizes of all user-defined types.
 9191 # We'll need the sizes of their elements, which may be other user-defined
 9192 # types, which we will compute as needed.
 9193 
 9194 # Initially, all user-defined types have their sizes set to -2 (invalid)
 9195 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 9196     # . prologue
 9197     55/push-ebp
 9198     89/<- %ebp 4/r32/esp
 9199 $populate-mu-type-sizes:total-sizes:
 9200     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 9201     (lookup *_Program-types *_Program-types->payload)  # => eax
 9202     {
 9203       # if (curr == null) break
 9204       3d/compare-eax-and 0/imm32/null
 9205       74/jump-if-= break/disp8
 9206       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
 9207       # curr = lookup(curr->next)
 9208       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 9209       eb/jump loop/disp8
 9210     }
 9211 $populate-mu-type-sizes:offsets:
 9212     # curr = *Program->types
 9213     (lookup *_Program-types *_Program-types->payload)  # => eax
 9214     {
 9215       # if (curr == null) break
 9216       3d/compare-eax-and 0/imm32/null
 9217       74/jump-if-= break/disp8
 9218       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
 9219       # curr = curr->next
 9220       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 9221       eb/jump loop/disp8
 9222     }
 9223 $populate-mu-type-sizes:end:
 9224     # . epilogue
 9225     89/<- %esp 5/r32/ebp
 9226     5d/pop-to-ebp
 9227     c3/return
 9228 
 9229 # compute sizes of all fields, recursing as necessary
 9230 # sum up all their sizes to arrive at total size
 9231 # fields may be out of order, but that doesn't affect the answer
 9232 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 9233     # . prologue
 9234     55/push-ebp
 9235     89/<- %ebp 4/r32/esp
 9236     # . save registers
 9237     50/push-eax
 9238     51/push-ecx
 9239     52/push-edx
 9240     56/push-esi
 9241     57/push-edi
 9242     # esi = T
 9243     8b/-> *(ebp+8) 6/r32/esi
 9244     # if T is already computed, return
 9245     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 9246     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 9247     # if T is being computed, abort
 9248     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 9249     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
 9250     # tag T (-2 to -1) to avoid infinite recursion
 9251     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 9252     # var total-size/edi: int = 0
 9253     bf/copy-to-edi 0/imm32
 9254     # - for every field, if it's a user-defined type, compute its size
 9255     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 9256     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 9257     89/<- %ecx 0/r32/eax
 9258     # var table-size/edx: int = table->write
 9259     8b/-> *ecx 2/r32/edx  # stream-write
 9260     # var curr/ecx: (addr table_row) = table->data
 9261     8d/copy-address *(ecx+0xc) 1/r32/ecx
 9262     # var max/edx: (addr table_row) = table->data + table->write
 9263     8d/copy-address *(ecx+edx) 2/r32/edx
 9264     {
 9265 $populate-mu-type-sizes-in-type:loop:
 9266       # if (curr >= max) break
 9267       39/compare %ecx 2/r32/edx
 9268       73/jump-if-addr>= break/disp8
 9269       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
 9270       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 9271       # compute size of t->input-var
 9272       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 9273       (compute-size-of-var %eax)  # => eax
 9274       # result += eax
 9275       01/add-to %edi 0/r32/eax
 9276       # curr += row-size
 9277       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 9278       #
 9279       eb/jump loop/disp8
 9280     }
 9281     # - save result
 9282     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
 9283 $populate-mu-type-sizes-in-type:end:
 9284     # . restore registers
 9285     5f/pop-to-edi
 9286     5e/pop-to-esi
 9287     5a/pop-to-edx
 9288     59/pop-to-ecx
 9289     58/pop-to-eax
 9290     # . epilogue
 9291     89/<- %esp 5/r32/ebp
 9292     5d/pop-to-ebp
 9293     c3/return
 9294 
 9295 $populate-mu-type-sizes-in-type:abort:
 9296     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
 9297     (flush *(ebp+0xc))
 9298     (stop *(ebp+0x10) 1)
 9299     # never gets here
 9300 
 9301 # Analogous to size-of, except we need to compute what size-of can just read
 9302 # off the right data structures.
 9303 compute-size-of-var:  # in: (addr var) -> result/eax: int
 9304     # . prologue
 9305     55/push-ebp
 9306     89/<- %ebp 4/r32/esp
 9307     # . push registers
 9308     51/push-ecx
 9309     # var t/ecx: (addr tree type-id) = lookup(v->type)
 9310     8b/-> *(ebp+8) 1/r32/ecx
 9311     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9312     89/<- %ecx 0/r32/eax
 9313     # if (t->is-atom == false) t = lookup(t->left)
 9314     {
 9315       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 9316       75/jump-if-!= break/disp8
 9317       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9318       89/<- %ecx 0/r32/eax
 9319     }
 9320     # TODO: ensure t is an atom
 9321     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
 9322 $compute-size-of-var:end:
 9323     # . restore registers
 9324     59/pop-to-ecx
 9325     # . epilogue
 9326     89/<- %esp 5/r32/ebp
 9327     5d/pop-to-ebp
 9328     c3/return
 9329 
 9330 compute-size-of-type-id:  # t: type-id -> result/eax: int
 9331     # . prologue
 9332     55/push-ebp
 9333     89/<- %ebp 4/r32/esp
 9334     # . save registers
 9335     51/push-ecx
 9336     # var out/ecx: (handle typeinfo)
 9337     68/push 0/imm32
 9338     68/push 0/imm32
 9339     89/<- %ecx 4/r32/esp
 9340     # eax = t
 9341     8b/-> *(ebp+8) 0/r32/eax
 9342     # if t is a literal, return 0
 9343     3d/compare-eax-and 0/imm32/literal
 9344     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
 9345     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
 9346     3d/compare-eax-and 8/imm32/byte
 9347     {
 9348       75/jump-if-!= break/disp8
 9349       b8/copy-to-eax 4/imm32
 9350       eb/jump $compute-size-of-type-id:end/disp8
 9351     }
 9352     # if t is a handle, return 8
 9353     3d/compare-eax-and 4/imm32/handle
 9354     {
 9355       75/jump-if-!= break/disp8
 9356       b8/copy-to-eax 8/imm32
 9357       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
 9358     }
 9359     # if t is a user-defined type, compute its size
 9360     # TODO: support non-atom type
 9361     (find-typeinfo %eax %ecx)
 9362     {
 9363       81 7/subop/compare *ecx 0/imm32
 9364       74/jump-if-= break/disp8
 9365 $compute-size-of-type-id:user-defined:
 9366       (populate-mu-type-sizes %eax)
 9367       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 9368       eb/jump $compute-size-of-type-id:end/disp8
 9369     }
 9370     # otherwise return the word size
 9371     b8/copy-to-eax 4/imm32
 9372 $compute-size-of-type-id:end:
 9373     # . reclaim locals
 9374     81 0/subop/add %esp 8/imm32
 9375     # . restore registers
 9376     59/pop-to-ecx
 9377     # . epilogue
 9378     89/<- %esp 5/r32/ebp
 9379     5d/pop-to-ebp
 9380     c3/return
 9381 
 9382 # at this point we have total sizes for all user-defined types
 9383 # compute offsets for each element
 9384 # complication: fields may be out of order
 9385 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 9386     # . prologue
 9387     55/push-ebp
 9388     89/<- %ebp 4/r32/esp
 9389     # . save registers
 9390     50/push-eax
 9391     51/push-ecx
 9392     52/push-edx
 9393     53/push-ebx
 9394     56/push-esi
 9395     57/push-edi
 9396 #?     (dump-typeinfos "aaa\n")
 9397     # var curr-offset/edi: int = 0
 9398     bf/copy-to-edi 0/imm32
 9399     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
 9400     8b/-> *(ebp+8) 1/r32/ecx
 9401     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
 9402     89/<- %ecx 0/r32/eax
 9403     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
 9404     8b/-> *ecx 2/r32/edx  # stream-write
 9405     c1 5/subop/shift-right-logical  %edx 4/imm8
 9406     # var i/ebx: int = 0
 9407     bb/copy-to-ebx 0/imm32
 9408     {
 9409 $populate-mu-type-offsets:loop:
 9410       39/compare %ebx 2/r32/edx
 9411       7d/jump-if->= break/disp8
 9412 #?       (write-buffered Stderr "looking up index ")
 9413 #?       (print-int32-buffered Stderr %ebx)
 9414 #?       (write-buffered Stderr " in ")
 9415 #?       (print-int32-buffered Stderr *(ebp+8))
 9416 #?       (write-buffered Stderr Newline)
 9417 #?       (flush Stderr)
 9418       # var v/esi: (addr typeinfo-entry)
 9419       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
 9420       89/<- %esi 0/r32/eax
 9421       # v->output-var->offset = curr-offset
 9422       # . eax: (addr var)
 9423       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
 9424       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
 9425       # curr-offset += size-of(v->input-var)
 9426       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 9427       (size-of %eax)  # => eax
 9428       01/add-to %edi 0/r32/eax
 9429       # ++i
 9430       43/increment-ebx
 9431       eb/jump loop/disp8
 9432     }
 9433 $populate-mu-type-offsets:end:
 9434     # . restore registers
 9435     5f/pop-to-edi
 9436     5e/pop-to-esi
 9437     5b/pop-to-ebx
 9438     5a/pop-to-edx
 9439     59/pop-to-ecx
 9440     58/pop-to-eax
 9441     # . epilogue
 9442     89/<- %esp 5/r32/ebp
 9443     5d/pop-to-ebp
 9444     c3/return
 9445 
 9446 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)
 9447     # . prologue
 9448     55/push-ebp
 9449     89/<- %ebp 4/r32/esp
 9450     # . save registers
 9451     51/push-ecx
 9452     52/push-edx
 9453     53/push-ebx
 9454     56/push-esi
 9455     57/push-edi
 9456     # esi = table
 9457     8b/-> *(ebp+8) 6/r32/esi
 9458     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
 9459     8d/copy-address *(esi+0xc) 1/r32/ecx
 9460     # var max/edx: (addr byte) = &table->data[table->write]
 9461     8b/-> *esi 2/r32/edx
 9462     8d/copy-address *(ecx+edx) 2/r32/edx
 9463     {
 9464 $locate-typeinfo-entry-with-index:loop:
 9465       39/compare %ecx 2/r32/edx
 9466       73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8
 9467       # var v/eax: (addr typeinfo-entry)
 9468       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 9469       # if (v->index == idx) return v
 9470       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
 9471 #?       (write-buffered Stderr "comparing ")
 9472 #?       (print-int32-buffered Stderr %ebx)
 9473 #?       (write-buffered Stderr " and ")
 9474 #?       (print-int32-buffered Stderr *(ebp+0xc))
 9475 #?       (write-buffered Stderr Newline)
 9476 #?       (flush Stderr)
 9477       39/compare *(ebp+0xc) 3/r32/ebx
 9478       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
 9479       # curr += Typeinfo-entry-size
 9480       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
 9481       #
 9482       eb/jump loop/disp8
 9483     }
 9484     # return 0
 9485     b8/copy-to-eax 0/imm32
 9486 $locate-typeinfo-entry-with-index:end:
 9487 #?     (write-buffered Stderr "returning ")
 9488 #?     (print-int32-buffered Stderr %eax)
 9489 #?     (write-buffered Stderr Newline)
 9490 #?     (flush Stderr)
 9491     # . restore registers
 9492     5f/pop-to-edi
 9493     5e/pop-to-esi
 9494     5b/pop-to-ebx
 9495     5a/pop-to-edx
 9496     59/pop-to-ecx
 9497     # . epilogue
 9498     89/<- %esp 5/r32/ebp
 9499     5d/pop-to-ebp
 9500     c3/return
 9501 
 9502 $locate-typeinfo-entry-with-index:abort:
 9503     (write-buffered *(ebp+0x10) "overflowing typeinfo-entry->index ")
 9504     (print-int32-buffered *(ebp+0x10) %ecx)
 9505     (write-buffered *(ebp+0x10) "\n")
 9506     (flush *(ebp+0x10))
 9507     (stop *(ebp+0x14) 1)
 9508     # never gets here
 9509 
 9510 dump-typeinfos:  # hdr: (addr array byte)
 9511     # . prologue
 9512     55/push-ebp
 9513     89/<- %ebp 4/r32/esp
 9514     # . save registers
 9515     50/push-eax
 9516     #
 9517     (write-buffered Stderr *(ebp+8))
 9518     (flush Stderr)
 9519     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 9520     (lookup *_Program-types *_Program-types->payload)  # => eax
 9521     {
 9522       # if (curr == null) break
 9523       3d/compare-eax-and 0/imm32
 9524       74/jump-if-= break/disp8
 9525       (write-buffered Stderr "---\n")
 9526       (flush Stderr)
 9527       (dump-typeinfo %eax)
 9528       # curr = lookup(curr->next)
 9529       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 9530       eb/jump loop/disp8
 9531     }
 9532 $dump-typeinfos:end:
 9533     # . restore registers
 9534     58/pop-to-eax
 9535     # . epilogue
 9536     89/<- %esp 5/r32/ebp
 9537     5d/pop-to-ebp
 9538     c3/return
 9539 
 9540 dump-typeinfo:  # in: (addr typeinfo)
 9541     # . prologue
 9542     55/push-ebp
 9543     89/<- %ebp 4/r32/esp
 9544     # . save registers
 9545     50/push-eax
 9546     51/push-ecx
 9547     52/push-edx
 9548     53/push-ebx
 9549     56/push-esi
 9550     57/push-edi
 9551     # esi = in
 9552     8b/-> *(ebp+8) 6/r32/esi
 9553     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 9554     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 9555     89/<- %ecx 0/r32/eax
 9556     (write-buffered Stderr "id:")
 9557     (print-int32-buffered Stderr *esi)
 9558     (write-buffered Stderr "\n")
 9559     (write-buffered Stderr "fields @ ")
 9560     (print-int32-buffered Stderr %ecx)
 9561     (write-buffered Stderr Newline)
 9562     (flush Stderr)
 9563     (write-buffered Stderr "  write: ")
 9564     (print-int32-buffered Stderr *ecx)
 9565     (write-buffered Stderr Newline)
 9566     (flush Stderr)
 9567     (write-buffered Stderr "  read: ")
 9568     (print-int32-buffered Stderr *(ecx+4))
 9569     (write-buffered Stderr Newline)
 9570     (flush Stderr)
 9571     (write-buffered Stderr "  size: ")
 9572     (print-int32-buffered Stderr *(ecx+8))
 9573     (write-buffered Stderr Newline)
 9574     (flush Stderr)
 9575     # var table-size/edx: int = table->write
 9576     8b/-> *ecx 2/r32/edx  # stream-write
 9577     # var curr/ecx: (addr table_row) = table->data
 9578     8d/copy-address *(ecx+0xc) 1/r32/ecx
 9579     # var max/edx: (addr table_row) = table->data + table->write
 9580     8d/copy-address *(ecx+edx) 2/r32/edx
 9581     {
 9582 $dump-typeinfo:loop:
 9583       # if (curr >= max) break
 9584       39/compare %ecx 2/r32/edx
 9585       0f 83/jump-if-addr>= break/disp32
 9586       (write-buffered Stderr "  row:\n")
 9587       (write-buffered Stderr "    key: ")
 9588       (print-int32-buffered Stderr *ecx)
 9589       (write-buffered Stderr ",")
 9590       (print-int32-buffered Stderr *(ecx+4))
 9591       (write-buffered Stderr " = '")
 9592       (lookup *ecx *(ecx+4))
 9593       (write-buffered Stderr %eax)
 9594       (write-buffered Stderr "' @ ")
 9595       (print-int32-buffered Stderr %eax)
 9596       (write-buffered Stderr Newline)
 9597       (flush Stderr)
 9598       (write-buffered Stderr "    value: ")
 9599       (print-int32-buffered Stderr *(ecx+8))
 9600       (write-buffered Stderr ",")
 9601       (print-int32-buffered Stderr *(ecx+0xc))
 9602       (write-buffered Stderr " = typeinfo-entry@")
 9603       (lookup *(ecx+8) *(ecx+0xc))
 9604       (print-int32-buffered Stderr %eax)
 9605       (write-buffered Stderr Newline)
 9606       (flush Stderr)
 9607       (write-buffered Stderr "        input var@")
 9608       (dump-var 5 %eax)
 9609       (lookup *(ecx+8) *(ecx+0xc))
 9610       (write-buffered Stderr "        index: ")
 9611       (print-int32-buffered Stderr *(eax+8))
 9612       (write-buffered Stderr Newline)
 9613       (flush Stderr)
 9614       (write-buffered Stderr "        output var@")
 9615       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 9616       (dump-var 5 %eax)
 9617       (flush Stderr)
 9618       # curr += row-size
 9619       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 9620       #
 9621       e9/jump loop/disp32
 9622     }
 9623 $dump-typeinfo:end:
 9624     # . restore registers
 9625     5f/pop-to-edi
 9626     5e/pop-to-esi
 9627     5b/pop-to-ebx
 9628     5a/pop-to-edx
 9629     59/pop-to-ecx
 9630     58/pop-to-eax
 9631     # . epilogue
 9632     89/<- %esp 5/r32/ebp
 9633     5d/pop-to-ebp
 9634     c3/return
 9635 
 9636 dump-var:  # indent: int, v: (addr handle var)
 9637     # . prologue
 9638     55/push-ebp
 9639     89/<- %ebp 4/r32/esp
 9640     # . save registers
 9641     50/push-eax
 9642     53/push-ebx
 9643     # eax = v
 9644     8b/-> *(ebp+0xc) 0/r32/eax
 9645     #
 9646     (print-int32-buffered Stderr *eax)
 9647     (write-buffered Stderr ",")
 9648     (print-int32-buffered Stderr *(eax+4))
 9649     (write-buffered Stderr "->")
 9650     (lookup *eax *(eax+4))
 9651     (print-int32-buffered Stderr %eax)
 9652     (write-buffered Stderr Newline)
 9653     (flush Stderr)
 9654     {
 9655       3d/compare-eax-and 0/imm32
 9656       0f 84/jump-if-= break/disp32
 9657       (emit-indent Stderr *(ebp+8))
 9658       (write-buffered Stderr "name: ")
 9659       89/<- %ebx 0/r32/eax
 9660       (print-int32-buffered Stderr *ebx)  # Var-name
 9661       (write-buffered Stderr ",")
 9662       (print-int32-buffered Stderr *(ebx+4))  # Var-name
 9663       (write-buffered Stderr "->")
 9664       (lookup *ebx *(ebx+4))  # Var-name
 9665       (print-int32-buffered Stderr %eax)
 9666       {
 9667         3d/compare-eax-and 0/imm32
 9668         74/jump-if-= break/disp8
 9669         (write-buffered Stderr Space)
 9670         (write-buffered Stderr %eax)
 9671       }
 9672       (write-buffered Stderr Newline)
 9673       (flush Stderr)
 9674       (emit-indent Stderr *(ebp+8))
 9675       (write-buffered Stderr "block depth: ")
 9676       (print-int32-buffered Stderr *(ebx+0x10))  # Var-block-depth
 9677       (write-buffered Stderr Newline)
 9678       (flush Stderr)
 9679       (emit-indent Stderr *(ebp+8))
 9680       (write-buffered Stderr "stack offset: ")
 9681       (print-int32-buffered Stderr *(ebx+0x14))  # Var-offset
 9682       (write-buffered Stderr Newline)
 9683       (flush Stderr)
 9684       (emit-indent Stderr *(ebp+8))
 9685       (write-buffered Stderr "reg: ")
 9686       (print-int32-buffered Stderr *(ebx+0x18))  # Var-register
 9687       (write-buffered Stderr ",")
 9688       (print-int32-buffered Stderr *(ebx+0x1c))  # Var-register
 9689       (write-buffered Stderr "->")
 9690       (flush Stderr)
 9691       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
 9692       (print-int32-buffered Stderr %eax)
 9693       {
 9694         3d/compare-eax-and 0/imm32
 9695         74/jump-if-= break/disp8
 9696         (write-buffered Stderr Space)
 9697         (write-buffered Stderr %eax)
 9698       }
 9699       (write-buffered Stderr Newline)
 9700       (flush Stderr)
 9701     }
 9702 $dump-var:end:
 9703     # . restore registers
 9704     5b/pop-to-ebx
 9705     58/pop-to-eax
 9706     # . epilogue
 9707     89/<- %esp 5/r32/ebp
 9708     5d/pop-to-ebp
 9709     c3/return
 9710 
 9711 #######################################################
 9712 # Type-checking
 9713 #######################################################
 9714 
 9715 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 9716     # . prologue
 9717     55/push-ebp
 9718     89/<- %ebp 4/r32/esp
 9719     # . save registers
 9720     50/push-eax
 9721     # var curr/eax: (addr function) = *Program->functions
 9722     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 9723     {
 9724 $check-mu-types:loop:
 9725       # if (curr == null) break
 9726       3d/compare-eax-and 0/imm32
 9727       0f 84/jump-if-= break/disp32
 9728       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
 9729       # curr = lookup(curr->next)
 9730       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 9731       e9/jump loop/disp32
 9732     }
 9733 $check-mu-types:end:
 9734     # . restore registers
 9735     58/pop-to-eax
 9736     # . epilogue
 9737     89/<- %esp 5/r32/ebp
 9738     5d/pop-to-ebp
 9739     c3/return
 9740 
 9741 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9742     # . prologue
 9743     55/push-ebp
 9744     89/<- %ebp 4/r32/esp
 9745     # . save registers
 9746     50/push-eax
 9747     # eax = f
 9748     8b/-> *(ebp+8) 0/r32/eax
 9749     # TODO: anything to check in header?
 9750     # var body/eax: (addr block) = lookup(f->body)
 9751     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
 9752     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 9753 $check-mu-function:end:
 9754     # . restore registers
 9755     58/pop-to-eax
 9756     # . epilogue
 9757     89/<- %esp 5/r32/ebp
 9758     5d/pop-to-ebp
 9759     c3/return
 9760 
 9761 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9762     # . prologue
 9763     55/push-ebp
 9764     89/<- %ebp 4/r32/esp
 9765     # . save registers
 9766     50/push-eax
 9767     # eax = block
 9768     8b/-> *(ebp+8) 0/r32/eax
 9769     # var stmts/eax: (addr list stmt) = lookup(block->statements)
 9770     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
 9771     #
 9772     {
 9773 $check-mu-block:check-empty:
 9774       3d/compare-eax-and 0/imm32
 9775       0f 84/jump-if-= break/disp32
 9776       # emit block->statements
 9777       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9778     }
 9779 $check-mu-block:end:
 9780     # . restore registers
 9781     58/pop-to-eax
 9782     # . epilogue
 9783     89/<- %esp 5/r32/ebp
 9784     5d/pop-to-ebp
 9785     c3/return
 9786 
 9787 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9788     # . prologue
 9789     55/push-ebp
 9790     89/<- %ebp 4/r32/esp
 9791     # . save registers
 9792     50/push-eax
 9793     56/push-esi
 9794     # esi = stmts
 9795     8b/-> *(ebp+8) 6/r32/esi
 9796     {
 9797 $check-mu-stmt-list:loop:
 9798       81 7/subop/compare %esi 0/imm32
 9799       0f 84/jump-if-= break/disp32
 9800       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
 9801       (lookup *esi *(esi+4))  # List-value List-value => eax
 9802       {
 9803 $check-mu-stmt-list:check-for-block:
 9804         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
 9805         75/jump-if-!= break/disp8
 9806 $check-mu-stmt-list:block:
 9807         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9808         eb/jump $check-mu-stmt-list:continue/disp8
 9809       }
 9810       {
 9811 $check-mu-stmt-list:check-for-stmt1:
 9812         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
 9813         0f 85/jump-if-!= break/disp32
 9814 $check-mu-stmt-list:stmt1:
 9815         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9816         eb/jump $check-mu-stmt-list:continue/disp8
 9817       }
 9818       {
 9819 $check-mu-stmt-list:check-for-reg-var-def:
 9820         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
 9821         0f 85/jump-if-!= break/disp32
 9822 $check-mu-stmt-list:reg-var-def:
 9823         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9824         eb/jump $check-mu-stmt-list:continue/disp8
 9825       }
 9826 $check-mu-stmt-list:continue:
 9827       # TODO: raise an error on unrecognized Stmt-tag
 9828       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
 9829       89/<- %esi 0/r32/eax
 9830       e9/jump loop/disp32
 9831     }
 9832 $check-mu-stmt-list:end:
 9833     # . restore registers
 9834     5e/pop-to-esi
 9835     58/pop-to-eax
 9836     # . epilogue
 9837     89/<- %esp 5/r32/ebp
 9838     5d/pop-to-ebp
 9839     c3/return
 9840 
 9841 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9842     # . prologue
 9843     55/push-ebp
 9844     89/<- %ebp 4/r32/esp
 9845     # . save registers
 9846     50/push-eax
 9847     51/push-ecx
 9848     52/push-edx
 9849     53/push-ebx
 9850     56/push-esi
 9851     57/push-edi
 9852     # esi = stmt
 9853     8b/-> *(ebp+8) 6/r32/esi
 9854     # var f/edi: (addr function) = lookup(*Program->functions)
 9855     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 9856     (find-matching-function %eax *(ebp+8))  # => eax
 9857     89/<- %edi 0/r32/eax
 9858     {
 9859 $check-mu-stmt:check-for-call:
 9860       81 7/subop/compare %edi 0/imm32
 9861       0f 84/jump-if-= break/disp32
 9862 $check-mu-stmt:is-call:
 9863       # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
 9864       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9865       89/<- %ecx 0/r32/eax
 9866       # var expected/edx: (addr list var) = lookup(f->inouts)
 9867       (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
 9868       89/<- %edx 0/r32/eax
 9869       {
 9870 $check-mu-stmt:check-for-inouts:
 9871         # if (inouts == 0) break
 9872         81 7/subop/compare %ecx 0/imm32
 9873         0f 84/jump-if-= break/disp32
 9874         # if (expected == 0) error
 9875         81 7/subop/compare %edx 0/imm32
 9876         0f 84/jump-if-= break/disp32
 9877 $check-mu-stmt:check-inout-type:
 9878         # var v/eax: (addr v) = lookup(inouts->value)
 9879         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9880         # var t/ebx: (addr tree type-id) = lookup(v->type)
 9881         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9882         89/<- %ebx 0/r32/eax
 9883         # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
 9884         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9885         {
 9886           74/jump-if-= break/disp8
 9887           (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
 9888           89/<- %ebx 0/r32/eax
 9889           # if t->right is null, t = t->left
 9890           81 7/subop/compare *(ebx+0xc) 0/imm32  # Tree-right
 9891           75/jump-if-!= break/disp8
 9892           (lookup *(ebx+4) *(ebx+8))  # Tree-left Tree-left => eax
 9893           89/<- %ebx 0/r32/eax
 9894         }
 9895         # var v2/eax: (addr v) = lookup(expected->value)
 9896         (lookup *edx *(edx+4))  # List-value List-value => eax
 9897         # var t2/eax: (addr tree type-id) = lookup(v2->type)
 9898         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9899         # if (t != t2) error
 9900         (type-match? %eax %ebx)  # => eax
 9901         3d/compare-eax-and 0/imm32/false
 9902         {
 9903           0f 85/jump-if-!= break/disp32
 9904           (write-buffered *(ebp+0x10) "fn ")
 9905           8b/-> *(ebp+0xc) 0/r32/eax
 9906           (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9907           (write-buffered *(ebp+0x10) %eax)
 9908           (write-buffered *(ebp+0x10) ": call ")
 9909           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9910           (write-buffered *(ebp+0x10) %eax)
 9911           (write-buffered *(ebp+0x10) ": type for inout '")
 9912           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9913           (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9914           (write-buffered *(ebp+0x10) %eax)
 9915           (write-buffered *(ebp+0x10) "' is not right\n")
 9916           (flush *(ebp+0x10))
 9917           (stop *(ebp+0x14) 1)
 9918         }
 9919 $check-mu-stmt:continue-to-next-inout:
 9920         # inouts = lookup(inouts->next)
 9921         (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9922         89/<- %ecx 0/r32/eax
 9923         # expected = lookup(expected->next)
 9924         (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 9925         89/<- %edx 0/r32/eax
 9926         #
 9927         e9/jump loop/disp32
 9928       }
 9929 $check-mu-stmt:check-inout-count:
 9930       # if (inouts == expected) proceed
 9931       39/compare %ecx 2/r32/edx
 9932       {
 9933         0f 84/jump-if-= break/disp32
 9934         # exactly one of the two is null
 9935         # if (inouts == 0) error("too many inouts")
 9936         {
 9937           81 7/subop/compare %ecx 0/imm32
 9938           0f 84/jump-if-= break/disp32
 9939           (write-buffered *(ebp+0x10) "fn ")
 9940           8b/-> *(ebp+0xc) 0/r32/eax
 9941           (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9942           (write-buffered *(ebp+0x10) %eax)
 9943           (write-buffered *(ebp+0x10) ": call ")
 9944           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9945           (write-buffered *(ebp+0x10) %eax)
 9946           (write-buffered *(ebp+0x10) ": too many inouts\n")
 9947           (flush *(ebp+0x10))
 9948           (stop *(ebp+0x14) 1)
 9949         }
 9950         # if (expected == 0) error("too few inouts")
 9951         {
 9952           81 7/subop/compare %edx 0/imm32
 9953           0f 84/jump-if-= break/disp32
 9954           (write-buffered *(ebp+0x10) "fn ")
 9955           8b/-> *(ebp+0xc) 0/r32/eax
 9956           (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9957           (write-buffered *(ebp+0x10) %eax)
 9958           (write-buffered *(ebp+0x10) ": call ")
 9959           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9960           (write-buffered *(ebp+0x10) %eax)
 9961           (write-buffered *(ebp+0x10) ": too few inouts\n")
 9962           (flush *(ebp+0x10))
 9963           (stop *(ebp+0x14) 1)
 9964         }
 9965       }
 9966 $check-mu-stmt:check-outputs:
 9967       # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
 9968       (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9969       89/<- %ecx 0/r32/eax
 9970       # var expected/edx: (addr list var) = lookup(f->outputs)
 9971       (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
 9972       89/<- %edx 0/r32/eax
 9973       {
 9974 $check-mu-stmt:check-for-outputs:
 9975         # if (outputs == 0) break
 9976         81 7/subop/compare %ecx 0/imm32
 9977         0f 84/jump-if-= break/disp32
 9978         # if (expected == 0) error
 9979         81 7/subop/compare %edx 0/imm32
 9980         0f 84/jump-if-= break/disp32
 9981 $check-mu-stmt:check-output-type:
 9982         # var v/eax: (addr v) = lookup(outputs->value)
 9983         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9984         # var t/ebx: (addr tree type-id) = lookup(v->type)
 9985         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9986         89/<- %ebx 0/r32/eax
 9987         # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
 9988         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9989         {
 9990           74/jump-if-= break/disp8
 9991           (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
 9992           89/<- %ebx 0/r32/eax
 9993         }
 9994         # var v2/eax: (addr v) = lookup(expected->value)
 9995         (lookup *edx *(edx+4))  # List-value List-value => eax
 9996         # var t2/eax: (addr tree type-id) = lookup(v2->type)
 9997         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9998         # if (t != t2) error
 9999         (type-equal? %eax %ebx)  # => eax
10000         3d/compare-eax-and 0/imm32/false
10001         {
10002           0f 85/jump-if-!= break/disp32
10003           (write-buffered *(ebp+0x10) "fn ")
10004           8b/-> *(ebp+0xc) 0/r32/eax
10005           (lookup *eax *(eax+4))  # Function-name Function-name => eax
10006           (write-buffered *(ebp+0x10) %eax)
10007           (write-buffered *(ebp+0x10) ": call ")
10008           (lookup *edi *(edi+4))  # Function-name Function-name => eax
10009           (write-buffered *(ebp+0x10) %eax)
10010           (write-buffered *(ebp+0x10) ": type for output '")
10011           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
10012           (lookup *eax *(eax+4))  # Var-name Var-name => eax
10013           (write-buffered *(ebp+0x10) %eax)
10014           (write-buffered *(ebp+0x10) "' is not right\n")
10015           (flush *(ebp+0x10))
10016           (stop *(ebp+0x14) 1)
10017         }
10018 $check-mu-stmt:check-output-register:
10019         # var v/eax: (addr v) = lookup(outputs->value)
10020         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
10021         # var r/ebx: (addr array byte) = lookup(v->register)
10022         (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
10023         89/<- %ebx 0/r32/eax
10024         # var v2/eax: (addr v) = lookup(expected->value)
10025         (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
10026         # var r2/eax: (addr array byte) = lookup(v2->register)
10027         (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
10028         # if (r != r2) error
10029         (string-equal? %eax %ebx)  # => eax
10030         3d/compare-eax-and 0/imm32/false
10031         {
10032           0f 85/jump-if-!= break/disp32
10033           (write-buffered *(ebp+0x10) "fn ")
10034           8b/-> *(ebp+0xc) 0/r32/eax
10035           (lookup *eax *(eax+4))  # Function-name Function-name => eax
10036           (write-buffered *(ebp+0x10) %eax)
10037           (write-buffered *(ebp+0x10) ": call ")
10038           (lookup *edi *(edi+4))  # Function-name Function-name => eax
10039           (write-buffered *(ebp+0x10) %eax)
10040           (write-buffered *(ebp+0x10) ": register for output '")
10041           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
10042           (lookup *eax *(eax+4))  # Var-name Var-name => eax
10043           (write-buffered *(ebp+0x10) %eax)
10044           (write-buffered *(ebp+0x10) "' is not right\n")
10045           (flush *(ebp+0x10))
10046           (stop *(ebp+0x14) 1)
10047         }
10048 $check-mu-stmt:continue-to-next-output:
10049         # outputs = lookup(outputs->next)
10050         (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
10051         89/<- %ecx 0/r32/eax
10052         # expected = lookup(expected->next)
10053         (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
10054         89/<- %edx 0/r32/eax
10055         #
10056         e9/jump loop/disp32
10057       }
10058 $check-mu-stmt:check-output-count:
10059       # if (outputs == expected) proceed
10060       39/compare %ecx 2/r32/edx
10061       {
10062         0f 84/jump-if-= break/disp32
10063         # exactly one of the two is null
10064         # if (outputs == 0) error("too many outputs")
10065         {
10066           81 7/subop/compare %ecx 0/imm32
10067           0f 84/jump-if-= break/disp32
10068           (write-buffered *(ebp+0x10) "fn ")
10069           8b/-> *(ebp+0xc) 0/r32/eax
10070           (lookup *eax *(eax+4))  # Function-name Function-name => eax
10071           (write-buffered *(ebp+0x10) %eax)
10072           (write-buffered *(ebp+0x10) ": call ")
10073           (lookup *edi *(edi+4))  # Function-name Function-name => eax
10074           (write-buffered *(ebp+0x10) %eax)
10075           (write-buffered *(ebp+0x10) ": too many outputs\n")
10076           (flush *(ebp+0x10))
10077           (stop *(ebp+0x14) 1)
10078         }
10079         # if (expected == 0) error("too few outputs")
10080         {
10081           81 7/subop/compare %edx 0/imm32
10082           0f 84/jump-if-= break/disp32
10083           (write-buffered *(ebp+0x10) "fn ")
10084           8b/-> *(ebp+0xc) 0/r32/eax
10085           (lookup *eax *(eax+4))  # Function-name Function-name => eax
10086           (write-buffered *(ebp+0x10) %eax)
10087           (write-buffered *(ebp+0x10) ": call ")
10088           (lookup *edi *(edi+4))  # Function-name Function-name => eax
10089           (write-buffered *(ebp+0x10) %eax)
10090           (write-buffered *(ebp+0x10) ": too few outputs\n")
10091           (flush *(ebp+0x10))
10092           (stop *(ebp+0x14) 1)
10093         }
10094       }
10095     }
10096 $check-mu-stmt:end:
10097     # . restore registers
10098     5f/pop-to-edi
10099     5e/pop-to-esi
10100     5b/pop-to-ebx
10101     5a/pop-to-edx
10102     59/pop-to-ecx
10103     58/pop-to-eax
10104     # . epilogue
10105     89/<- %esp 5/r32/ebp
10106     5d/pop-to-ebp
10107     c3/return
10108 
10109 # like type-equal? but takes literals into account
10110 type-match?:  # def: (addr tree type-id), call: (addr tree type-id) -> result/eax: boolean
10111     # . prologue
10112     55/push-ebp
10113     89/<- %ebp 4/r32/esp
10114     # if (call == literal) return true  # TODO: more precise
10115     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
10116     3d/compare-eax-and 0/imm32/false
10117     b8/copy-to-eax 1/imm32/true
10118     75/jump-if-!= $type-match?:end/disp8
10119 $type-match?:baseline:
10120     # otherwise fall back
10121     (type-equal? *(ebp+8) *(ebp+0xc))  # => eax
10122 $type-match?:end:
10123     # . epilogue
10124     89/<- %esp 5/r32/ebp
10125     5d/pop-to-ebp
10126     c3/return
10127 
10128 size-of:  # v: (addr var) -> result/eax: int
10129     # . prologue
10130     55/push-ebp
10131     89/<- %ebp 4/r32/esp
10132     # . save registers
10133     51/push-ecx
10134     # var t/ecx: (addr tree type-id) = lookup(v->type)
10135     8b/-> *(ebp+8) 1/r32/ecx
10136 #?     (write-buffered Stderr "size-of ")
10137 #?     (print-int32-buffered Stderr %ecx)
10138 #?     (write-buffered Stderr Newline)
10139 #?     (write-buffered Stderr "type allocid: ")
10140 #?     (print-int32-buffered Stderr *(ecx+8))
10141 #?     (write-buffered Stderr Newline)
10142 #?     (flush Stderr)
10143     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10144     89/<- %ecx 0/r32/eax
10145     # if is-mu-array?(t) return size-of-array(t)
10146     {
10147       (is-mu-array? %ecx)  # => eax
10148       3d/compare-eax-and 0/imm32/false
10149       74/jump-if-= break/disp8
10150       (size-of-array %ecx)  # => eax
10151       eb/jump $size-of:end/disp8
10152     }
10153     # if (!t->is-atom?) t = lookup(t->left)
10154     {
10155       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
10156       75/jump-if-!= break/disp8
10157       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10158       89/<- %ecx 0/r32/eax
10159     }
10160     # TODO: assert t->is-atom?
10161     (size-of-type-id *(ecx+4))  # Tree-value => eax
10162 $size-of:end:
10163     # . restore registers
10164     59/pop-to-ecx
10165     # . epilogue
10166     89/<- %esp 5/r32/ebp
10167     5d/pop-to-ebp
10168     c3/return
10169 
10170 size-of-deref:  # v: (addr var) -> result/eax: int
10171     # . prologue
10172     55/push-ebp
10173     89/<- %ebp 4/r32/esp
10174     # . save registers
10175     51/push-ecx
10176     # var t/ecx: (addr tree type-id) = lookup(v->type)
10177     8b/-> *(ebp+8) 1/r32/ecx
10178     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10179     89/<- %ecx 0/r32/eax
10180     # TODO: assert(t is an addr)
10181     # t = lookup(t->right)
10182     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
10183     89/<- %ecx 0/r32/eax
10184     # if is-mu-array?(t) return size-of-array(t)
10185     {
10186       (is-mu-array? %ecx)  # => eax
10187       3d/compare-eax-and 0/imm32/false
10188       74/jump-if-= break/disp8
10189       (size-of-array %ecx)  # => eax
10190       eb/jump $size-of:end/disp8
10191     }
10192     # if (!t->is-atom?) t = lookup(t->left)
10193     {
10194       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
10195       75/jump-if-!= break/disp8
10196       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10197       89/<- %ecx 0/r32/eax
10198     }
10199     # TODO: assert t->is-atom?
10200     (size-of-type-id *(ecx+4))  # Tree-value => eax
10201 $size-of-deref:end:
10202     # . restore registers
10203     59/pop-to-ecx
10204     # . epilogue
10205     89/<- %esp 5/r32/ebp
10206     5d/pop-to-ebp
10207     c3/return
10208 
10209 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
10210     # . prologue
10211     55/push-ebp
10212     89/<- %ebp 4/r32/esp
10213     # . save registers
10214     51/push-ecx
10215     # ecx = t
10216     8b/-> *(ebp+8) 1/r32/ecx
10217     # if t->is-atom?, return false
10218     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
10219     75/jump-if-!= $is-mu-array?:return-false/disp8
10220     # if !t->left->is-atom?, return false
10221     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10222     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
10223     74/jump-if-= $is-mu-array?:return-false/disp8
10224     # return t->left->value == array
10225     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
10226     0f 94/set-if-= %al
10227     81 4/subop/and %eax 0xff/imm32
10228     eb/jump $is-mu-array?:end/disp8
10229 $is-mu-array?:return-false:
10230     b8/copy-to-eax 0/imm32/false
10231 $is-mu-array?:end:
10232     # . restore registers
10233     59/pop-to-ecx
10234     # . epilogue
10235     89/<- %esp 5/r32/ebp
10236     5d/pop-to-ebp
10237     c3/return
10238 
10239 size-of-array:  # a: (addr tree type-id) -> result/eax: int
10240     # . prologue
10241     55/push-ebp
10242     89/<- %ebp 4/r32/esp
10243     # . save registers
10244     51/push-ecx
10245     52/push-edx
10246     #
10247     8b/-> *(ebp+8) 1/r32/ecx
10248     # TODO: assert that a->left is 'array'
10249     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
10250     89/<- %ecx 0/r32/eax
10251     # var elem-type/edx: type-id = a->right->left->value
10252     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10253     8b/-> *(eax+4) 2/r32/edx  # Tree-value
10254     # var array-size/ecx: int = a->right->right->left->value
10255     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
10256     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
10257     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
10258     # return array-size * size-of(elem-type)
10259     (size-of-type-id-as-array-element %edx)  # => eax
10260     f7 4/subop/multiply-into-eax %ecx
10261     05/add-to-eax 4/imm32  # for array size
10262 $size-of-array:end:
10263     # . restore registers
10264     5a/pop-to-edx
10265     59/pop-to-ecx
10266     # . epilogue
10267     89/<- %esp 5/r32/ebp
10268     5d/pop-to-ebp
10269     c3/return
10270 
10271 size-of-type-id:  # t: type-id -> result/eax: int
10272     # . prologue
10273     55/push-ebp
10274     89/<- %ebp 4/r32/esp
10275     # . save registers
10276     51/push-ecx
10277     # var out/ecx: (handle typeinfo)
10278     68/push 0/imm32
10279     68/push 0/imm32
10280     89/<- %ecx 4/r32/esp
10281     # eax = t
10282     8b/-> *(ebp+8) 0/r32/eax
10283     # if t is a literal, return 0
10284     3d/compare-eax-and 0/imm32
10285     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
10286     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
10287     3d/compare-eax-and 8/imm32/byte
10288     {
10289       75/jump-if-!= break/disp8
10290       b8/copy-to-eax 4/imm32
10291       eb/jump $size-of-type-id:end/disp8
10292     }
10293     # if t is a handle, return 8
10294     3d/compare-eax-and 4/imm32/handle
10295     {
10296       75/jump-if-!= break/disp8
10297       b8/copy-to-eax 8/imm32
10298       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
10299     }
10300     # if t is a user-defined type, return its size
10301     # TODO: support non-atom type
10302     (find-typeinfo %eax %ecx)
10303     {
10304       81 7/subop/compare *ecx 0/imm32
10305       74/jump-if-= break/disp8
10306 $size-of-type-id:user-defined:
10307       (lookup *ecx *(ecx+4))  # => eax
10308       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
10309       eb/jump $size-of-type-id:end/disp8
10310     }
10311     # otherwise return the word size
10312     b8/copy-to-eax 4/imm32
10313 $size-of-type-id:end:
10314     # . reclaim locals
10315     81 0/subop/add %esp 8/imm32
10316     # . restore registers
10317     59/pop-to-ecx
10318     # . epilogue
10319     89/<- %esp 5/r32/ebp
10320     5d/pop-to-ebp
10321     c3/return
10322 
10323 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
10324     # . prologue
10325     55/push-ebp
10326     89/<- %ebp 4/r32/esp
10327     # . save registers
10328     51/push-ecx
10329     52/push-edx
10330     53/push-ebx
10331     # ecx = a
10332     8b/-> *(ebp+8) 1/r32/ecx
10333     # edx = b
10334     8b/-> *(ebp+0xc) 2/r32/edx
10335 $type-equal?:compare-addr:
10336     # if (a == b) return true
10337     8b/-> %ecx 0/r32/eax  # Var-type
10338     39/compare %edx 0/r32/eax  # Var-type
10339     b8/copy-to-eax 1/imm32/true
10340     0f 84/jump-if-= $type-equal?:end/disp32
10341 $type-equal?:compare-atom-state:
10342     # if (a->is-atom? != b->is-atom?) return false
10343     8b/-> *ecx 3/r32/ebx  # Tree-value
10344     39/compare *edx 3/r32/ebx  # Tree-value
10345     b8/copy-to-eax 0/imm32/false
10346     0f 85/jump-if-!= $type-equal?:end/disp32
10347     # if a->is-atom? return (a->value == b->value)
10348     {
10349 $type-equal?:check-atom:
10350       81 7/subop/compare %ebx 0/imm32/false
10351       74/jump-if-= break/disp8
10352 $type-equal?:is-atom:
10353       8b/-> *(ecx+4) 0/r32/eax  # Tree-value
10354       39/compare *(edx+4) 0/r32/eax  # Tree-value
10355       0f 94/set-if-= %al
10356       81 4/subop/and %eax 0xff/imm32
10357       e9/jump $type-equal?:end/disp32
10358     }
10359 $type-equal?:check-left:
10360     # if (!type-equal?(a->left, b->left)) return false
10361     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
10362     89/<- %ebx 0/r32/eax
10363     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
10364     (type-equal? %eax %ebx)  # => eax
10365     3d/compare-eax-and 0/imm32/false
10366     74/jump-if-= $type-equal?:end/disp8
10367 $type-equal?:check-right:
10368     # return type-equal?(a->right, b->right)
10369     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
10370     89/<- %ebx 0/r32/eax
10371     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
10372     (type-equal? %eax %ebx)  # => eax
10373 $type-equal?:end:
10374     # . restore registers
10375     5b/pop-to-ebx
10376     5a/pop-to-edx
10377     59/pop-to-ecx
10378     # . epilogue
10379     89/<- %esp 5/r32/ebp
10380     5d/pop-to-ebp
10381     c3/return
10382 
10383 #######################################################
10384 # Code-generation
10385 #######################################################
10386 
10387 == data
10388 
10389 # Global state added to each var record when performing code-generation.
10390 Curr-local-stack-offset:  # (addr int)
10391     0/imm32
10392 
10393 == code
10394 
10395 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
10396     # . prologue
10397     55/push-ebp
10398     89/<- %ebp 4/r32/esp
10399     # . save registers
10400     50/push-eax
10401     # var curr/eax: (addr function) = *Program->functions
10402     (lookup *_Program-functions *_Program-functions->payload)  # => eax
10403     {
10404       # if (curr == null) break
10405       3d/compare-eax-and 0/imm32
10406       0f 84/jump-if-= break/disp32
10407       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
10408       # curr = lookup(curr->next)
10409       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
10410       e9/jump loop/disp32
10411     }
10412 $emit-subx:end:
10413     # . restore registers
10414     58/pop-to-eax
10415     # . epilogue
10416     89/<- %esp 5/r32/ebp
10417     5d/pop-to-ebp
10418     c3/return
10419 
10420 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10421     # . prologue
10422     55/push-ebp
10423     89/<- %ebp 4/r32/esp
10424     # some preprocessing
10425     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
10426     # . save registers
10427     50/push-eax
10428     51/push-ecx
10429     52/push-edx
10430     # initialize some global state
10431     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
10432     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
10433     # ecx = f
10434     8b/-> *(ebp+0xc) 1/r32/ecx
10435     # var vars/edx: (stack (addr var) 256)
10436     81 5/subop/subtract %esp 0xc00/imm32
10437     68/push 0xc00/imm32/size
10438     68/push 0/imm32/top
10439     89/<- %edx 4/r32/esp
10440     # var name/eax: (addr array byte) = lookup(f->name)
10441     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
10442     #
10443     (write-buffered *(ebp+8) %eax)
10444     (write-buffered *(ebp+8) ":\n")
10445     (emit-subx-prologue *(ebp+8))
10446     # var body/eax: (addr block) = lookup(f->body)
10447     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
10448     #
10449     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10450     (emit-subx-epilogue *(ebp+8))
10451     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
10452     # been cleaned up
10453 $emit-subx-function:end:
10454     # . reclaim locals
10455     81 0/subop/add %esp 0xc08/imm32
10456     # . restore registers
10457     5a/pop-to-edx
10458     59/pop-to-ecx
10459     58/pop-to-eax
10460     # . epilogue
10461     89/<- %esp 5/r32/ebp
10462     5d/pop-to-ebp
10463     c3/return
10464 
10465 populate-mu-type-offsets-in-inouts:  # f: (addr function)
10466     # . prologue
10467     55/push-ebp
10468     89/<- %ebp 4/r32/esp
10469     # . save registers
10470     50/push-eax
10471     51/push-ecx
10472     52/push-edx
10473     53/push-ebx
10474     57/push-edi
10475     # var next-offset/edx: int = 8
10476     ba/copy-to-edx 8/imm32
10477     # var curr/ecx: (addr list var) = lookup(f->inouts)
10478     8b/-> *(ebp+8) 1/r32/ecx
10479     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
10480     89/<- %ecx 0/r32/eax
10481     {
10482 $populate-mu-type-offsets-in-inouts:loop:
10483       81 7/subop/compare %ecx 0/imm32
10484       74/jump-if-= break/disp8
10485       # var v/ebx: (addr var) = lookup(curr->value)
10486       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10487       89/<- %ebx 0/r32/eax
10488 #?       (lookup *ebx *(ebx+4))
10489 #?       (write-buffered Stderr "setting offset of fn inout ")
10490 #?       (write-buffered Stderr %eax)
10491 #?       (write-buffered Stderr "@")
10492 #?       (print-int32-buffered Stderr %ebx)
10493 #?       (write-buffered Stderr " to ")
10494 #?       (print-int32-buffered Stderr %edx)
10495 #?       (write-buffered Stderr Newline)
10496 #?       (flush Stderr)
10497       # v->offset = next-offset
10498       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
10499       # next-offset += size-of(v)
10500       (size-of %ebx)  # => eax
10501       01/add-to %edx 0/r32/eax
10502       # curr = lookup(curr->next)
10503       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10504       89/<- %ecx 0/r32/eax
10505       #
10506       eb/jump loop/disp8
10507     }
10508 $populate-mu-type-offsets-in-inouts:end:
10509     # . restore registers
10510     5f/pop-to-edi
10511     5b/pop-to-ebx
10512     5a/pop-to-edx
10513     59/pop-to-ecx
10514     58/pop-to-eax
10515     # . epilogue
10516     89/<- %esp 5/r32/ebp
10517     5d/pop-to-ebp
10518     c3/return
10519 
10520 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)
10521     # . prologue
10522     55/push-ebp
10523     89/<- %ebp 4/r32/esp
10524     # . save registers
10525     50/push-eax
10526     51/push-ecx
10527     53/push-ebx
10528     56/push-esi
10529     # esi = stmts
10530     8b/-> *(ebp+0xc) 6/r32/esi
10531     #
10532     {
10533 $emit-subx-stmt-list:loop:
10534       81 7/subop/compare %esi 0/imm32
10535       0f 84/jump-if-= break/disp32
10536       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
10537       (lookup *esi *(esi+4))  # List-value List-value => eax
10538       89/<- %ecx 0/r32/eax
10539       {
10540 $emit-subx-stmt-list:check-for-block:
10541         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
10542         75/jump-if-!= break/disp8
10543 $emit-subx-stmt-list:block:
10544         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10545       }
10546       {
10547 $emit-subx-stmt-list:check-for-stmt:
10548         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
10549         0f 85/jump-if-!= break/disp32
10550 $emit-subx-stmt-list:stmt1:
10551         {
10552           (is-mu-branch? %ecx)  # => eax
10553           3d/compare-eax-and 0/imm32/false
10554           0f 84/jump-if-= break/disp32
10555 $emit-subx-stmt-list:branch-stmt:
10556 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
10583 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
10599 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
10637 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
10656         }
10657 $emit-subx-stmt-list:1-to-1:
10658         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
10659         e9/jump $emit-subx-stmt-list:continue/disp32
10660       }
10661       {
10662 $emit-subx-stmt-list:check-for-var-def:
10663         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
10664         75/jump-if-!= break/disp8
10665 $emit-subx-stmt-list:var-def:
10666         (emit-subx-var-def *(ebp+8) %ecx)
10667         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
10668         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
10669         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
10670         #
10671         eb/jump $emit-subx-stmt-list:continue/disp8
10672       }
10673       {
10674 $emit-subx-stmt-list:check-for-reg-var-def:
10675         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
10676         0f 85/jump-if-!= break/disp32
10677 $emit-subx-stmt-list:reg-var-def:
10678         # TODO: ensure that there's exactly one output
10679         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10680         # emit the instruction as usual
10681         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
10682         #
10683         eb/jump $emit-subx-stmt-list:continue/disp8
10684       }
10685 $emit-subx-stmt-list:continue:
10686       # TODO: raise an error on unrecognized Stmt-tag
10687       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
10688       89/<- %esi 0/r32/eax
10689       e9/jump loop/disp32
10690     }
10691 $emit-subx-stmt-list:emit-cleanup:
10692     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
10693 $emit-subx-stmt-list:clean-up:
10694     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
10695 $emit-subx-stmt-list:end:
10696     # . restore registers
10697     5e/pop-to-esi
10698     5b/pop-to-ebx
10699     59/pop-to-ecx
10700     58/pop-to-eax
10701     # . epilogue
10702     89/<- %esp 5/r32/ebp
10703     5d/pop-to-ebp
10704     c3/return
10705 
10706 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
10707 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)
10708     # . prologue
10709     55/push-ebp
10710     89/<- %ebp 4/r32/esp
10711     # . save registers
10712     50/push-eax
10713     51/push-ecx
10714     52/push-edx
10715     # ecx = stmt
10716     8b/-> *(ebp+0xc) 1/r32/ecx
10717     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
10718     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10719     # TODO: assert !sv->is-deref?
10720     # var v/ecx: (addr var) = lookup(sv->value)
10721     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10722     89/<- %ecx 0/r32/eax
10723     # v->block-depth = *Curr-block-depth
10724     8b/-> *Curr-block-depth 0/r32/eax
10725     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10726 #?     (write-buffered Stderr "var ")
10727 #?     (lookup *ecx *(ecx+4))
10728 #?     (write-buffered Stderr %eax)
10729 #?     (write-buffered Stderr " at depth ")
10730 #?     (print-int32-buffered Stderr *(ecx+0x10))
10731 #?     (write-buffered Stderr Newline)
10732 #?     (flush Stderr)
10733     # ensure that v is in a register
10734     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
10735     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
10736     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
10737     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
10738     89/<- %edx 0/r32/eax
10739     3d/compare-eax-and 0/imm32/false
10740     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
10741     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
10742     89/<- %edx 0/r32/eax
10743     # check emit-spill?
10744     3d/compare-eax-and 0/imm32/false
10745     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
10746     # TODO: assert(size-of(output) == 4)
10747     # *Curr-local-stack-offset -= 4
10748     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
10749     # emit spill
10750     (emit-indent *(ebp+8) *Curr-block-depth)
10751     (write-buffered *(ebp+8) "ff 6/subop/push %")
10752     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10753     (write-buffered *(ebp+8) %eax)
10754     (write-buffered *(ebp+8) Newline)
10755 $push-output-and-maybe-emit-spill:push:
10756     8b/-> *(ebp+0xc) 1/r32/ecx
10757     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10758     # push(vars, {sv->value, emit-spill?})
10759     (push *(ebp+0x10) *eax)  # Stmt-var-value
10760     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
10761     (push *(ebp+0x10) %edx)
10762 $push-output-and-maybe-emit-spill:end:
10763     # . restore registers
10764     5a/pop-to-edx
10765     59/pop-to-ecx
10766     58/pop-to-eax
10767     # . epilogue
10768     89/<- %esp 5/r32/ebp
10769     5d/pop-to-ebp
10770     c3/return
10771 
10772 $push-output-and-maybe-emit-spill:abort:
10773     # error("var '" var->name "' initialized from an instruction must live in a register\n")
10774     (write-buffered *(ebp+0x1c) "var '")
10775     (write-buffered *(ebp+0x1c) *eax)  # Var-name
10776     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
10777     (flush *(ebp+0x1c))
10778     (stop *(ebp+0x20) 1)
10779     # never gets here
10780 
10781 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
10782     # . prologue
10783     55/push-ebp
10784     89/<- %ebp 4/r32/esp
10785     # . save registers
10786     50/push-eax
10787     51/push-ecx
10788     # ecx = stmt
10789     8b/-> *(ebp+0xc) 1/r32/ecx
10790     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
10791     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10792     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10793     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10794     # clean up until target block
10795     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
10796     # emit jump to target block
10797     (emit-indent *(ebp+8) *Curr-block-depth)
10798     (write-buffered *(ebp+8) "e9/jump ")
10799     (write-buffered *(ebp+8) %eax)
10800     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
10801     (string-starts-with? %eax "break")
10802     3d/compare-eax-and 0/imm32/false
10803     {
10804       74/jump-if-= break/disp8
10805       (write-buffered *(ebp+8) ":break/disp32\n")
10806     }
10807     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
10808     {
10809       75/jump-if-!= break/disp8
10810       (write-buffered *(ebp+8) ":loop/disp32\n")
10811     }
10812 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
10813     # . restore registers
10814     59/pop-to-ecx
10815     58/pop-to-eax
10816     # . epilogue
10817     89/<- %esp 5/r32/ebp
10818     5d/pop-to-ebp
10819     c3/return
10820 
10821 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
10822     # . prologue
10823     55/push-ebp
10824     89/<- %ebp 4/r32/esp
10825     # . save registers
10826     51/push-ecx
10827     # ecx = lookup(stmt->operation)
10828     8b/-> *(ebp+8) 1/r32/ecx
10829     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
10830     89/<- %ecx 0/r32/eax
10831     # if (stmt->operation starts with "loop") return true
10832     (string-starts-with? %ecx "loop")  # => eax
10833     3d/compare-eax-and 0/imm32/false
10834     75/jump-if-not-equal $is-mu-branch?:end/disp8
10835     # otherwise return (stmt->operation starts with "break")
10836     (string-starts-with? %ecx "break")  # => eax
10837 $is-mu-branch?:end:
10838     # . restore registers
10839     59/pop-to-ecx
10840     # . epilogue
10841     89/<- %esp 5/r32/ebp
10842     5d/pop-to-ebp
10843     c3/return
10844 
10845 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
10846     # . prologue
10847     55/push-ebp
10848     89/<- %ebp 4/r32/esp
10849     # . save registers
10850     50/push-eax
10851     # eax = stmt
10852     8b/-> *(ebp+0xc) 0/r32/eax
10853     #
10854     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
10855     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
10856     (emit-indent *(ebp+8) *Curr-block-depth)
10857     (lookup *eax *(eax+4))  # => eax
10858     (write-buffered *(ebp+8) %eax)
10859     (write-buffered *(ebp+8) " break/disp32\n")
10860 $emit-reverse-break:end:
10861     # . restore registers
10862     58/pop-to-eax
10863     # . epilogue
10864     89/<- %esp 5/r32/ebp
10865     5d/pop-to-ebp
10866     c3/return
10867 
10868 == data
10869 
10870 # Table from Mu branch instructions to the reverse SubX opcodes for them.
10871 Reverse-branch:  # (table (handle array byte) (handle array byte))
10872   # a table is a stream
10873   0x140/imm32/write
10874   0/imm32/read
10875   0x140/imm32/size
10876   # data
10877   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
10878   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
10879   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
10880   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
10881   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
10882   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
10883   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
10884   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
10885   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10886   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10887   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
10888   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
10889   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
10890   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
10891   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
10892   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
10893   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10894   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10895   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
10896   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
10897 
10898 == code
10899 
10900 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
10901     # . prologue
10902     55/push-ebp
10903     89/<- %ebp 4/r32/esp
10904     # . save registers
10905     50/push-eax
10906     51/push-ecx
10907     52/push-edx
10908     53/push-ebx
10909     56/push-esi
10910     # ecx = vars
10911     8b/-> *(ebp+0xc) 1/r32/ecx
10912     # var eax: int = vars->top
10913     8b/-> *ecx 0/r32/eax
10914     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10915     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
10916     # var min/ecx: (addr handle var) = vars->data
10917     8d/copy-address *(ecx+8) 1/r32/ecx
10918     # edx = depth
10919     8b/-> *(ebp+0x10) 2/r32/edx
10920     {
10921 $emit-unconditional-jump-to-depth:loop:
10922       # if (curr < min) break
10923       39/compare %esi 1/r32/ecx
10924       0f 82/jump-if-addr< break/disp32
10925       # var v/ebx: (addr var) = lookup(*curr)
10926       (lookup *esi *(esi+4))  # => eax
10927       89/<- %ebx 0/r32/eax
10928       # if (v->block-depth < until-block-depth) break
10929       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
10930       0f 8c/jump-if-< break/disp32
10931       {
10932 $emit-unconditional-jump-to-depth:check:
10933         # if v->block-depth != until-block-depth, continue
10934         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
10935         0f 85/jump-if-!= break/disp32
10936 $emit-unconditional-jump-to-depth:depth-found:
10937         # if v is not a literal, continue
10938         (size-of %ebx)  # => eax
10939         3d/compare-eax-and 0/imm32
10940         0f 85/jump-if-!= break/disp32
10941 $emit-unconditional-jump-to-depth:label-found:
10942         # emit unconditional jump, then return
10943         (emit-indent *(ebp+8) *Curr-block-depth)
10944         (write-buffered *(ebp+8) "e9/jump ")
10945         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
10946         (write-buffered *(ebp+8) %eax)
10947         (write-buffered *(ebp+8) ":")
10948         (write-buffered *(ebp+8) *(ebp+0x14))
10949         (write-buffered *(ebp+8) "/disp32\n")
10950         eb/jump $emit-unconditional-jump-to-depth:end/disp8
10951       }
10952       # curr -= 12
10953       81 5/subop/subtract %esi 0xc/imm32
10954       e9/jump loop/disp32
10955     }
10956     # TODO: error if no label at 'depth' was found
10957 $emit-unconditional-jump-to-depth:end:
10958     # . restore registers
10959     5e/pop-to-esi
10960     5b/pop-to-ebx
10961     5a/pop-to-edx
10962     59/pop-to-ecx
10963     58/pop-to-eax
10964     # . epilogue
10965     89/<- %esp 5/r32/ebp
10966     5d/pop-to-ebp
10967     c3/return
10968 
10969 # emit clean-up code for 'vars' until some block depth
10970 # doesn't actually modify 'vars' so we need traverse manually inside the stack
10971 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
10972     # . prologue
10973     55/push-ebp
10974     89/<- %ebp 4/r32/esp
10975     # . save registers
10976     50/push-eax
10977     51/push-ecx
10978     52/push-edx
10979     53/push-ebx
10980     56/push-esi
10981 #?     (write-buffered Stderr "--- cleanup\n")
10982 #?     (flush Stderr)
10983     # ecx = vars
10984     8b/-> *(ebp+0xc) 1/r32/ecx
10985     # var esi: int = vars->top
10986     8b/-> *ecx 6/r32/esi
10987     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10988     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
10989     # var min/ecx: (addr handle var) = vars->data
10990     81 0/subop/add %ecx 8/imm32
10991     # edx = until-block-depth
10992     8b/-> *(ebp+0x10) 2/r32/edx
10993     {
10994 $emit-cleanup-code-until-depth:loop:
10995       # if (curr < min) break
10996       39/compare %esi 1/r32/ecx
10997       0f 82/jump-if-addr< break/disp32
10998       # var v/ebx: (addr var) = lookup(*curr)
10999       (lookup *esi *(esi+4))  # => eax
11000       89/<- %ebx 0/r32/eax
11001 #?       (lookup *ebx *(ebx+4))  # Var-name
11002 #?       (write-buffered Stderr "var ")
11003 #?       (write-buffered Stderr %eax)
11004 #?       (write-buffered Stderr Newline)
11005 #?       (flush Stderr)
11006       # if (v->block-depth < until-block-depth) break
11007       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
11008       0f 8c/jump-if-< break/disp32
11009       # if v is in a register
11010       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
11011       {
11012         0f 84/jump-if-= break/disp32
11013         {
11014 $emit-cleanup-code-until-depth:check-for-previous-spill:
11015           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
11016           3d/compare-eax-and 0/imm32/false
11017           74/jump-if-= break/disp8
11018 $emit-cleanup-code-until-depth:reclaim-var-in-register:
11019           (emit-indent *(ebp+8) *Curr-block-depth)
11020           (write-buffered *(ebp+8) "8f 0/subop/pop %")
11021           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
11022           (write-buffered *(ebp+8) %eax)
11023           (write-buffered *(ebp+8) Newline)
11024         }
11025         eb/jump $emit-cleanup-code-until-depth:continue/disp8
11026       }
11027       # otherwise v is on the stack
11028       {
11029         75/jump-if-!= break/disp8
11030 $emit-cleanup-code-until-depth:var-on-stack:
11031         (size-of %ebx)  # => eax
11032         # don't emit code for labels
11033         3d/compare-eax-and 0/imm32
11034         74/jump-if-= break/disp8
11035 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
11036         (emit-indent *(ebp+8) *Curr-block-depth)
11037         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
11038         (print-int32-buffered *(ebp+8) %eax)
11039         (write-buffered *(ebp+8) "/imm32\n")
11040       }
11041 $emit-cleanup-code-until-depth:continue:
11042       # curr -= 12
11043       81 5/subop/subtract %esi 0xc/imm32
11044       e9/jump loop/disp32
11045     }
11046 $emit-cleanup-code-until-depth:end:
11047     # . restore registers
11048     5e/pop-to-esi
11049     5b/pop-to-ebx
11050     5a/pop-to-edx
11051     59/pop-to-ecx
11052     58/pop-to-eax
11053     # . epilogue
11054     89/<- %esp 5/r32/ebp
11055     5d/pop-to-ebp
11056     c3/return
11057 
11058 # emit clean-up code for 'vars' until a given label is encountered
11059 # doesn't actually modify 'vars' so we need traverse manually inside the stack
11060 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
11061     # . prologue
11062     55/push-ebp
11063     89/<- %ebp 4/r32/esp
11064     # . save registers
11065     50/push-eax
11066     51/push-ecx
11067     52/push-edx
11068     53/push-ebx
11069     # ecx = vars
11070     8b/-> *(ebp+0xc) 1/r32/ecx
11071     # var eax: int = vars->top
11072     8b/-> *ecx 0/r32/eax
11073     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
11074     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
11075     # var min/ecx: (addr handle var) = vars->data
11076     81 0/subop/add %ecx 8/imm32
11077     {
11078 $emit-cleanup-code-until-target:loop:
11079       # if (curr < min) break
11080       39/compare %edx 1/r32/ecx
11081       0f 82/jump-if-addr< break/disp32
11082       # var v/ebx: (handle var) = lookup(*curr)
11083       (lookup *edx *(edx+4))  # => eax
11084       89/<- %ebx 0/r32/eax
11085       # if (v->name == until-block-label) break
11086       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
11087       (string-equal? %eax *(ebp+0x10))  # => eax
11088       3d/compare-eax-and 0/imm32/false
11089       0f 85/jump-if-!= break/disp32
11090       # if v is in a register
11091       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
11092       {
11093         0f 84/jump-if-= break/disp32
11094         {
11095 $emit-cleanup-code-until-target:check-for-previous-spill:
11096           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
11097           3d/compare-eax-and 0/imm32/false
11098           74/jump-if-= break/disp8
11099 $emit-cleanup-code-until-target:reclaim-var-in-register:
11100           (emit-indent *(ebp+8) *Curr-block-depth)
11101           (write-buffered *(ebp+8) "8f 0/subop/pop %")
11102           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
11103           (write-buffered *(ebp+8) %eax)
11104           (write-buffered *(ebp+8) Newline)
11105         }
11106         eb/jump $emit-cleanup-code-until-target:continue/disp8
11107       }
11108       # otherwise v is on the stack
11109       {
11110         75/jump-if-!= break/disp8
11111 $emit-cleanup-code-until-target:reclaim-var-on-stack:
11112         (size-of %ebx)  # => eax
11113         # don't emit code for labels
11114         3d/compare-eax-and 0/imm32
11115         74/jump-if-= break/disp8
11116         #
11117         (emit-indent *(ebp+8) *Curr-block-depth)
11118         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
11119         (print-int32-buffered *(ebp+8) %eax)
11120         (write-buffered *(ebp+8) "/imm32\n")
11121       }
11122 $emit-cleanup-code-until-target:continue:
11123       # curr -= 12
11124       81 5/subop/subtract %edx 0xc/imm32
11125       e9/jump loop/disp32
11126     }
11127 $emit-cleanup-code-until-target:end:
11128     # . restore registers
11129     5b/pop-to-ebx
11130     5a/pop-to-edx
11131     59/pop-to-ecx
11132     58/pop-to-eax
11133     # . epilogue
11134     89/<- %esp 5/r32/ebp
11135     5d/pop-to-ebp
11136     c3/return
11137 
11138 # Return true if there isn't a variable in 'vars' with the same block-depth
11139 # and register as 'v'.
11140 # 'v' is guaranteed not to be within 'vars'.
11141 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
11142     # . prologue
11143     55/push-ebp
11144     89/<- %ebp 4/r32/esp
11145     # . save registers
11146     51/push-ecx
11147     52/push-edx
11148     53/push-ebx
11149     56/push-esi
11150     57/push-edi
11151     # ecx = vars
11152     8b/-> *(ebp+0xc) 1/r32/ecx
11153     # var eax: int = vars->top
11154     8b/-> *ecx 0/r32/eax
11155     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
11156     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
11157     # var min/ecx: (addr handle var) = vars->data
11158     8d/copy-address *(ecx+8) 1/r32/ecx
11159     # var depth/ebx: int = v->block-depth
11160     8b/-> *(ebp+8) 3/r32/ebx
11161     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
11162     # var needle/esi: (addr array byte) = v->register
11163     8b/-> *(ebp+8) 6/r32/esi
11164     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
11165     89/<- %esi 0/r32/eax
11166     {
11167 $not-yet-spilled-this-block?:loop:
11168       # if (curr < min) break
11169       39/compare %edx 1/r32/ecx
11170       0f 82/jump-if-addr< break/disp32
11171       # var cand/edi: (addr var) = lookup(*curr)
11172       (lookup *edx *(edx+4))  # => eax
11173       89/<- %edi 0/r32/eax
11174       # if (cand->block-depth < depth) break
11175       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
11176       0f 8c/jump-if-< break/disp32
11177       # var cand-reg/edi: (array array byte) = cand->reg
11178       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
11179       89/<- %edi 0/r32/eax
11180       # if (cand-reg == null) continue
11181       {
11182 $not-yet-spilled-this-block?:check-reg:
11183         81 7/subop/compare %edi 0/imm32
11184         0f 84/jump-if-= break/disp32
11185         # if (cand-reg == needle) return true
11186         (string-equal? %esi %edi)  # => eax
11187         3d/compare-eax-and 0/imm32/false
11188         74/jump-if-= break/disp8
11189 $not-yet-spilled-this-block?:return-false:
11190         b8/copy-to-eax 0/imm32/false
11191         eb/jump $not-yet-spilled-this-block?:end/disp8
11192       }
11193 $not-yet-spilled-this-block?:continue:
11194       # curr -= 12
11195       81 5/subop/subtract %edx 0xc/imm32
11196       e9/jump loop/disp32
11197     }
11198 $not-yet-spilled-this-block?:return-true:
11199     # return true
11200     b8/copy-to-eax 1/imm32/true
11201 $not-yet-spilled-this-block?:end:
11202     # . restore registers
11203     5f/pop-to-edi
11204     5e/pop-to-esi
11205     5b/pop-to-ebx
11206     5a/pop-to-edx
11207     59/pop-to-ecx
11208     # . epilogue
11209     89/<- %esp 5/r32/ebp
11210     5d/pop-to-ebp
11211     c3/return
11212 
11213 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
11214 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
11215     # . prologue
11216     55/push-ebp
11217     89/<- %ebp 4/r32/esp
11218     # eax = v
11219     8b/-> *(ebp+8) 0/r32/eax
11220     # var reg/eax: (addr array byte) = lookup(v->register)
11221     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11222     # var target/eax: (addr var) = find-register(fn-outputs, reg)
11223     (find-register *(ebp+0x10) %eax)  # => eax
11224     # if (target == 0) return true
11225     {
11226       3d/compare-eax-and 0/imm32
11227       75/jump-if-!= break/disp8
11228       b8/copy-to-eax 1/imm32/true
11229       eb/jump $will-not-write-some-register?:end/disp8
11230     }
11231     # return !assigns-in-stmts?(stmts, target)
11232     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
11233     3d/compare-eax-and 0/imm32/false
11234     # assume: true = 1, so no need to mask with 0x000000ff
11235     0f 94/set-if-= %al
11236 $will-not-write-some-register?:end:
11237     # . epilogue
11238     89/<- %esp 5/r32/ebp
11239     5d/pop-to-ebp
11240     c3/return
11241 
11242 # return fn output with matching register
11243 # always returns false if 'reg' is null
11244 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
11245     # . prologue
11246     55/push-ebp
11247     89/<- %ebp 4/r32/esp
11248     # . save registers
11249     51/push-ecx
11250     # var curr/ecx: (addr list var) = lookup(fn->outputs)
11251     8b/-> *(ebp+8) 1/r32/ecx
11252     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
11253     89/<- %ecx 0/r32/eax
11254     {
11255 $find-register:loop:
11256       # if (curr == 0) break
11257       81 7/subop/compare %ecx 0/imm32
11258       74/jump-if-= break/disp8
11259       # eax = curr->value->register
11260       (lookup *ecx *(ecx+4))  # List-value List-value => eax
11261       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11262       # if (eax == reg) return curr->value
11263 $find-register:compare:
11264       (string-equal? *(ebp+0xc) %eax)  # => eax
11265       {
11266         3d/compare-eax-and 0/imm32/false
11267         74/jump-if-= break/disp8
11268 $find-register:found:
11269         (lookup *ecx *(ecx+4))  # List-value List-value => eax
11270         eb/jump $find-register:end/disp8
11271       }
11272       # curr = lookup(curr->next)
11273       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
11274       89/<- %ecx 0/r32/eax
11275       #
11276       eb/jump loop/disp8
11277     }
11278 $find-register:end:
11279     # . restore registers
11280     59/pop-to-ecx
11281     # . epilogue
11282     89/<- %esp 5/r32/ebp
11283     5d/pop-to-ebp
11284     c3/return
11285 
11286 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
11287     # . prologue
11288     55/push-ebp
11289     89/<- %ebp 4/r32/esp
11290     # . save registers
11291     51/push-ecx
11292     # var curr/ecx: (addr list stmt) = stmts
11293     8b/-> *(ebp+8) 1/r32/ecx
11294     {
11295       # if (curr == 0) break
11296       81 7/subop/compare %ecx 0/imm32
11297       74/jump-if-= break/disp8
11298       # if assigns-in-stmt?(curr->value, v) return true
11299       (lookup *ecx *(ecx+4))  # List-value List-value => eax
11300       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
11301       3d/compare-eax-and 0/imm32/false
11302       75/jump-if-!= break/disp8
11303       # curr = lookup(curr->next)
11304       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
11305       89/<- %ecx 0/r32/eax
11306       #
11307       eb/jump loop/disp8
11308     }
11309 $assigns-in-stmts?:end:
11310     # . restore registers
11311     59/pop-to-ecx
11312     # . epilogue
11313     89/<- %esp 5/r32/ebp
11314     5d/pop-to-ebp
11315     c3/return
11316 
11317 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
11318     # . prologue
11319     55/push-ebp
11320     89/<- %ebp 4/r32/esp
11321     # . save registers
11322     51/push-ecx
11323     # ecx = stmt
11324     8b/-> *(ebp+8) 1/r32/ecx
11325     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
11326     {
11327       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
11328       75/jump-if-!= break/disp8
11329       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11330       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
11331       eb/jump $assigns-in-stmt?:end/disp8
11332     }
11333     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
11334     {
11335       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
11336       75/jump-if-!= break/disp8
11337       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
11338       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
11339       eb/jump $assigns-in-stmt?:end/disp8
11340     }
11341     # otherwise return false
11342     b8/copy 0/imm32/false
11343 $assigns-in-stmt?:end:
11344     # . restore registers
11345     59/pop-to-ecx
11346     # . epilogue
11347     89/<- %esp 5/r32/ebp
11348     5d/pop-to-ebp
11349     c3/return
11350 
11351 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
11352     # . prologue
11353     55/push-ebp
11354     89/<- %ebp 4/r32/esp
11355     # . save registers
11356     51/push-ecx
11357     # var curr/ecx: (addr stmt-var) = stmt-var
11358     8b/-> *(ebp+8) 1/r32/ecx
11359     {
11360       # if (curr == 0) break
11361       81 7/subop/compare %ecx 0/imm32
11362       74/jump-if-= break/disp8
11363       # eax = lookup(curr->value)
11364       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11365       # if (eax == v  &&  curr->is-deref? == false) return true
11366       {
11367         39/compare *(ebp+0xc) 0/r32/eax
11368         75/jump-if-!= break/disp8
11369         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
11370         75/jump-if-!= break/disp8
11371         b8/copy-to-eax 1/imm32/true
11372         eb/jump $assigns-in-stmt-vars?:end/disp8
11373       }
11374       # curr = lookup(curr->next)
11375       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
11376       89/<- %ecx 0/r32/eax
11377       #
11378       eb/jump loop/disp8
11379     }
11380 $assigns-in-stmt-vars?:end:
11381     # . restore registers
11382     59/pop-to-ecx
11383     # . epilogue
11384     89/<- %esp 5/r32/ebp
11385     5d/pop-to-ebp
11386     c3/return
11387 
11388 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
11389 # v is guaranteed to be within vars
11390 # 'start' is provided as an optimization, a pointer within vars
11391 # *start == v
11392 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
11393     # . prologue
11394     55/push-ebp
11395     89/<- %ebp 4/r32/esp
11396     # . save registers
11397     51/push-ecx
11398     52/push-edx
11399     53/push-ebx
11400     56/push-esi
11401     57/push-edi
11402     # ecx = v
11403     8b/-> *(ebp+8) 1/r32/ecx
11404     # var reg/edx: (addr array byte) = lookup(v->register)
11405     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
11406     89/<- %edx 0/r32/eax
11407     # var depth/ebx: int = v->block-depth
11408     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
11409     # var min/ecx: (addr handle var) = vars->data
11410     8b/-> *(ebp+0xc) 1/r32/ecx
11411     81 0/subop/add %ecx 8/imm32
11412     # TODO: check that start >= min and start < &vars->data[top]
11413     # TODO: check that *start == v
11414     # var curr/esi: (addr handle var) = start
11415     8b/-> *(ebp+0x10) 6/r32/esi
11416     # curr -= 8
11417     81 5/subop/subtract %esi 8/imm32
11418     {
11419 $same-register-spilled-before?:loop:
11420       # if (curr < min) break
11421       39/compare %esi 1/r32/ecx
11422       0f 82/jump-if-addr< break/disp32
11423       # var x/eax: (addr var) = lookup(*curr)
11424       (lookup *esi *(esi+4))  # => eax
11425       # if (x->block-depth < depth) break
11426       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
11427       0f 8c/jump-if-< break/disp32
11428       # if (x->register == 0) continue
11429       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
11430       74/jump-if-= $same-register-spilled-before?:continue/disp8
11431       # if (x->register == reg) return true
11432       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11433       (string-equal? %eax %edx)  # => eax
11434       3d/compare-eax-and 0/imm32/false
11435       b8/copy-to-eax 1/imm32/true
11436       75/jump-if-!= $same-register-spilled-before?:end/disp8
11437 $same-register-spilled-before?:continue:
11438       # curr -= 8
11439       81 5/subop/subtract %esi 8/imm32
11440       e9/jump loop/disp32
11441     }
11442 $same-register-spilled-before?:false:
11443     b8/copy-to-eax 0/imm32/false
11444 $same-register-spilled-before?:end:
11445     # . restore registers
11446     5f/pop-to-edi
11447     5e/pop-to-esi
11448     5b/pop-to-ebx
11449     5a/pop-to-edx
11450     59/pop-to-ecx
11451     # . epilogue
11452     89/<- %esp 5/r32/ebp
11453     5d/pop-to-ebp
11454     c3/return
11455 
11456 # Clean up global state for 'vars' until some block depth (inclusive).
11457 #
11458 # This would be a simple series of pops, if it wasn't for fn outputs, which
11459 # can occur anywhere in the stack.
11460 # So we have to _compact_ the entire array underlying the stack.
11461 #
11462 # We want to allow a fn output register to be written to by locals before the
11463 # output is set.
11464 # So fn outputs can't just be pushed at the start of the function.
11465 #
11466 # We want to allow other locals to shadow a fn output register after the
11467 # output is set.
11468 # So the output can't just always override anything in the stack. Sequence matters.
11469 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
11470     # pseudocode:
11471     #   to = vars->top  (which points outside the stack)
11472     #   while true
11473     #     if to <= 0
11474     #       break
11475     #     var v = vars->data[to-1]
11476     #     if v.depth < until and !in-function-outputs?(fn, v)
11477     #       break
11478     #     --to
11479     #   from = to
11480     #   while true
11481     #     if from >= vars->top
11482     #       break
11483     #     assert(from >= to)
11484     #     v = vars->data[from]
11485     #     if in-function-outputs?(fn, v)
11486     #       if from > to
11487     #         vars->data[to] = vars->data[from]
11488     #       ++to
11489     #     ++from
11490     #   vars->top = to
11491     #
11492     # . prologue
11493     55/push-ebp
11494     89/<- %ebp 4/r32/esp
11495     # . save registers
11496     50/push-eax
11497     52/push-edx
11498     53/push-ebx
11499     56/push-esi
11500     57/push-edi
11501     # ebx = vars
11502     8b/-> *(ebp+8) 3/r32/ebx
11503     # edx = until-block-depth
11504     8b/-> *(ebp+0xc) 2/r32/edx
11505 $clean-up-blocks:phase1:
11506     # var to/edi: int = vars->top
11507     8b/-> *ebx 7/r32/edi
11508     {
11509 $clean-up-blocks:loop1:
11510       # if (to <= 0) break
11511       81 7/subop/compare %edi 0/imm32
11512       7e/jump-if-<= break/disp8
11513       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
11514       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
11515       (lookup *eax *(eax+4))  # => eax
11516       # if (v->block-depth >= until-block-depth) continue
11517       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
11518       {
11519         7d/jump-if->= break/disp8
11520         # if (!in-function-outputs?(fn, v)) break
11521         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
11522         3d/compare-eax-and 0/imm32/false
11523         74/jump-if-= $clean-up-blocks:phase2/disp8
11524       }
11525 $clean-up-blocks:loop1-continue:
11526       # --to
11527       81 5/subop/subtract %edi 0xc/imm32
11528       #
11529       eb/jump loop/disp8
11530     }
11531 $clean-up-blocks:phase2:
11532     # var from/esi: int = to
11533     89/<- %esi 7/r32/edi
11534     {
11535 $clean-up-blocks:loop2:
11536       # if (from >= vars->top) break
11537       3b/compare 6/r32/esi *ebx
11538       7d/jump-if->= break/disp8
11539       # var v/eax: (addr var) = lookup(vars->data[from]->var)
11540       8d/copy-address *(ebx+esi+8) 0/r32/eax
11541       (lookup *eax *(eax+4))  # => eax
11542       # if !in-function-outputs?(fn, v) continue
11543       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
11544       3d/compare-eax-and 0/imm32/false
11545       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
11546       # invariant: from >= to
11547       # if (from > to) vars->data[to] = vars->data[from]
11548       {
11549         39/compare %esi 7/r32/edi
11550         7e/jump-if-<= break/disp8
11551         56/push-esi
11552         57/push-edi
11553         # . var from/esi: (addr byte) = &vars->data[from]
11554         8d/copy-address *(ebx+esi+8) 6/r32/esi
11555         # . var to/edi: (addr byte) = &vars->data[to]
11556         8d/copy-address *(ebx+edi+8) 7/r32/edi
11557         # .
11558         8b/-> *esi 0/r32/eax
11559         89/<- *edi 0/r32/eax
11560         8b/-> *(esi+4) 0/r32/eax
11561         89/<- *(edi+4) 0/r32/eax
11562         8b/-> *(esi+8) 0/r32/eax
11563         89/<- *(edi+8) 0/r32/eax
11564         5f/pop-to-edi
11565         5e/pop-to-esi
11566       }
11567       # ++to
11568       81 0/subop/add %edi 0xc/imm32
11569 $clean-up-blocks:loop2-continue:
11570       # ++from
11571       81 0/subop/add %esi 0xc/imm32
11572       #
11573       eb/jump loop/disp8
11574     }
11575     89/<- *ebx 7/r32/edi
11576 $clean-up-blocks:end:
11577     # . restore registers
11578     5f/pop-to-edi
11579     5e/pop-to-esi
11580     5b/pop-to-ebx
11581     5a/pop-to-edx
11582     58/pop-to-eax
11583     # . epilogue
11584     89/<- %esp 5/r32/ebp
11585     5d/pop-to-ebp
11586     c3/return
11587 
11588 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
11589     # . prologue
11590     55/push-ebp
11591     89/<- %ebp 4/r32/esp
11592     # . save registers
11593     51/push-ecx
11594     # var curr/ecx: (addr list var) = lookup(fn->outputs)
11595     8b/-> *(ebp+8) 1/r32/ecx
11596     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
11597     89/<- %ecx 0/r32/eax
11598     # while curr != null
11599     {
11600       81 7/subop/compare %ecx 0/imm32
11601       74/jump-if-= break/disp8
11602       # var v/eax: (addr var) = lookup(curr->value)
11603       (lookup *ecx *(ecx+4))  # List-value List-value => eax
11604       # if (v == target) return true
11605       39/compare *(ebp+0xc) 0/r32/eax
11606       b8/copy-to-eax 1/imm32/true
11607       74/jump-if-= $in-function-outputs?:end/disp8
11608       # curr = curr->next
11609       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
11610       89/<- %ecx 0/r32/eax
11611       #
11612       eb/jump loop/disp8
11613     }
11614     b8/copy-to-eax 0/imm32
11615 $in-function-outputs?:end:
11616     # . restore registers
11617     59/pop-to-ecx
11618     # . epilogue
11619     89/<- %esp 5/r32/ebp
11620     5d/pop-to-ebp
11621     c3/return
11622 
11623 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
11624     # . prologue
11625     55/push-ebp
11626     89/<- %ebp 4/r32/esp
11627     # . save registers
11628     50/push-eax
11629     51/push-ecx
11630     52/push-edx
11631     # eax = stmt
11632     8b/-> *(ebp+0xc) 0/r32/eax
11633     # var v/ecx: (addr var)
11634     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
11635     89/<- %ecx 0/r32/eax
11636     # v->block-depth = *Curr-block-depth
11637     8b/-> *Curr-block-depth 0/r32/eax
11638     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
11639     # var n/edx: int = size-of(stmt->var)
11640     (size-of %ecx)  # => eax
11641     89/<- %edx 0/r32/eax
11642     # *Curr-local-stack-offset -= n
11643     29/subtract-from *Curr-local-stack-offset 2/r32/edx
11644     # v->offset = *Curr-local-stack-offset
11645     8b/-> *Curr-local-stack-offset 0/r32/eax
11646     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
11647     # if v is an array, do something special
11648     {
11649       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11650       (is-mu-array? %eax)  # => eax
11651       3d/compare-eax-and 0/imm32/false
11652       0f 84/jump-if-= break/disp32
11653       # var array-size-without-size/edx: int = n-4
11654       81 5/subop/subtract %edx 4/imm32
11655       (emit-indent *(ebp+8) *Curr-block-depth)
11656       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
11657       (print-int32-buffered *(ebp+8) %edx)
11658       (write-buffered *(ebp+8) ")\n")
11659       (emit-indent *(ebp+8) *Curr-block-depth)
11660       (write-buffered *(ebp+8) "68/push ")
11661       (print-int32-buffered *(ebp+8) %edx)
11662       (write-buffered *(ebp+8) "/imm32\n")
11663       eb/jump $emit-subx-var-def:end/disp8
11664     }
11665     # while n > 0
11666     {
11667       81 7/subop/compare %edx 0/imm32
11668       7e/jump-if-<= break/disp8
11669       (emit-indent *(ebp+8) *Curr-block-depth)
11670       (write-buffered *(ebp+8) "68/push 0/imm32\n")
11671       # n -= 4
11672       81 5/subop/subtract %edx 4/imm32
11673       #
11674       eb/jump loop/disp8
11675     }
11676 $emit-subx-var-def:end:
11677     # . restore registers
11678     5a/pop-to-edx
11679     59/pop-to-ecx
11680     58/pop-to-eax
11681     # . epilogue
11682     89/<- %esp 5/r32/ebp
11683     5d/pop-to-ebp
11684     c3/return
11685 
11686 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
11687     # . prologue
11688     55/push-ebp
11689     89/<- %ebp 4/r32/esp
11690     # . save registers
11691     50/push-eax
11692     51/push-ecx
11693     # - some special-case primitives that don't actually use the 'primitives' data structure
11694     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11695     8b/-> *(ebp+0xc) 1/r32/ecx
11696     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
11697     89/<- %ecx 0/r32/eax
11698     # array size
11699     {
11700       # if (!string-equal?(stmt->operation, "length")) break
11701       (string-equal? %ecx "length")  # => eax
11702       3d/compare-eax-and 0/imm32
11703       0f 84/jump-if-= break/disp32
11704       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
11705       e9/jump $emit-subx-stmt:end/disp32
11706     }
11707     # index into array
11708     {
11709       # if (!string-equal?(stmt->operation, "index")) break
11710       (string-equal? %ecx "index")  # => eax
11711       3d/compare-eax-and 0/imm32
11712       0f 84/jump-if-= break/disp32
11713       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
11714       e9/jump $emit-subx-stmt:end/disp32
11715     }
11716     # compute-offset for index into array
11717     {
11718       # if (!string-equal?(stmt->operation, "compute-offset")) break
11719       (string-equal? %ecx "compute-offset")  # => eax
11720       3d/compare-eax-and 0/imm32
11721       0f 84/jump-if-= break/disp32
11722       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
11723       e9/jump $emit-subx-stmt:end/disp32
11724     }
11725     # get field from record
11726     {
11727       # if (!string-equal?(stmt->operation, "get")) break
11728       (string-equal? %ecx "get")  # => eax
11729       3d/compare-eax-and 0/imm32
11730       0f 84/jump-if-= break/disp32
11731       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
11732       e9/jump $emit-subx-stmt:end/disp32
11733     }
11734     # - if stmt matches a primitive, emit it
11735     {
11736 $emit-subx-stmt:check-for-primitive:
11737       # var curr/eax: (addr primitive)
11738       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
11739       3d/compare-eax-and 0/imm32
11740       74/jump-if-= break/disp8
11741 $emit-subx-stmt:primitive:
11742       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
11743       e9/jump $emit-subx-stmt:end/disp32
11744     }
11745     # - otherwise emit a call
11746     # TODO: type-checking
11747 $emit-subx-stmt:call:
11748     (emit-call *(ebp+8) *(ebp+0xc))
11749 $emit-subx-stmt:end:
11750     # . restore registers
11751     59/pop-to-ecx
11752     58/pop-to-eax
11753     # . epilogue
11754     89/<- %esp 5/r32/ebp
11755     5d/pop-to-ebp
11756     c3/return
11757 
11758 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11759     # . prologue
11760     55/push-ebp
11761     89/<- %ebp 4/r32/esp
11762     # . save registers
11763     50/push-eax
11764     51/push-ecx
11765     52/push-edx
11766     53/push-ebx
11767     56/push-esi
11768     # esi = stmt
11769     8b/-> *(ebp+0xc) 6/r32/esi
11770     # var base/ebx: (addr var) = stmt->inouts[0]->value
11771     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11772     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11773     89/<- %ebx 0/r32/eax
11774     # var elemsize/ecx: int = array-element-size(base)
11775     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
11776     89/<- %ecx 0/r32/eax
11777     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
11778     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11779     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11780     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11781     89/<- %edx 0/r32/eax
11782     # if elemsize == 1
11783     {
11784       81 7/subop/compare %ecx 1/imm32
11785       75/jump-if-!= break/disp8
11786 $translate-mu-length-stmt:size-1:
11787       (emit-save-size-to *(ebp+8) %ebx %edx)
11788       e9/jump $translate-mu-length-stmt:end/disp32
11789     }
11790     # if elemsize is a power of 2 less than 256
11791     {
11792       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
11793       3d/compare-eax-and 0/imm32/false
11794       74/jump-if-= break/disp8
11795       81 7/subop/compare %ecx 0xff/imm32
11796       7f/jump-if-> break/disp8
11797 $translate-mu-length-stmt:size-power-of-2:
11798       (emit-save-size-to *(ebp+8) %ebx %edx)
11799       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
11800       e9/jump $translate-mu-length-stmt:end/disp32
11801     }
11802     # otherwise, the complex case
11803     # . emit register spills
11804     {
11805 $translate-mu-length-stmt:complex:
11806       (string-equal? %edx "eax")  # => eax
11807       3d/compare-eax-and 0/imm32/false
11808       75/break-if-!= break/disp8
11809       (emit-indent *(ebp+8) *Curr-block-depth)
11810       (write-buffered *(ebp+8) "50/push-eax\n")
11811     }
11812     {
11813       (string-equal? %edx "ecx")  # => eax
11814       3d/compare-eax-and 0/imm32/false
11815       75/break-if-!= break/disp8
11816       (emit-indent *(ebp+8) *Curr-block-depth)
11817       (write-buffered *(ebp+8) "51/push-ecx\n")
11818     }
11819     {
11820       (string-equal? %edx "edx")  # => eax
11821       3d/compare-eax-and 0/imm32/false
11822       75/break-if-!= break/disp8
11823       (emit-indent *(ebp+8) *Curr-block-depth)
11824       (write-buffered *(ebp+8) "52/push-edx\n")
11825     }
11826     # .
11827     (emit-save-size-to *(ebp+8) %ebx "eax")
11828     (emit-indent *(ebp+8) *Curr-block-depth)
11829     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
11830     (emit-indent *(ebp+8) *Curr-block-depth)
11831     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
11832     (print-int32-buffered *(ebp+8) %ecx)
11833     (write-buffered *(ebp+8) "/imm32\n")
11834     (emit-indent *(ebp+8) *Curr-block-depth)
11835     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
11836     {
11837       (string-equal? %edx "eax")  # => eax
11838       3d/compare-eax-and 0/imm32/false
11839       75/break-if-!= break/disp8
11840       (emit-indent *(ebp+8) *Curr-block-depth)
11841       (write-buffered *(ebp+8) "89/<- %")
11842       (write-buffered *(ebp+8) %edx)
11843       (write-buffered *(ebp+8) " 0/r32/eax\n")
11844     }
11845     # . emit register restores
11846     {
11847       (string-equal? %edx "edx")  # => eax
11848       3d/compare-eax-and 0/imm32/false
11849       75/break-if-!= break/disp8
11850       (emit-indent *(ebp+8) *Curr-block-depth)
11851       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
11852     }
11853     {
11854       (string-equal? %edx "ecx")  # => eax
11855       3d/compare-eax-and 0/imm32/false
11856       75/break-if-!= break/disp8
11857       (emit-indent *(ebp+8) *Curr-block-depth)
11858       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
11859     }
11860     {
11861       (string-equal? %edx "eax")  # => eax
11862       3d/compare-eax-and 0/imm32/false
11863       75/break-if-!= break/disp8
11864       (emit-indent *(ebp+8) *Curr-block-depth)
11865       (write-buffered *(ebp+8) "58/pop-to-eax\n")
11866     }
11867 $translate-mu-length-stmt:end:
11868     # . restore registers
11869     5e/pop-to-esi
11870     5b/pop-to-ebx
11871     5a/pop-to-edx
11872     59/pop-to-ecx
11873     58/pop-to-eax
11874     # . epilogue
11875     89/<- %esp 5/r32/ebp
11876     5d/pop-to-ebp
11877     c3/return
11878 
11879 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11880     # . prologue
11881     55/push-ebp
11882     89/<- %ebp 4/r32/esp
11883     #
11884     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
11885     (size-of-type-id-as-array-element %eax)  # => eax
11886 $array-element-size:end:
11887     # . epilogue
11888     89/<- %esp 5/r32/ebp
11889     5d/pop-to-ebp
11890     c3/return
11891 
11892 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
11893     # . prologue
11894     55/push-ebp
11895     89/<- %ebp 4/r32/esp
11896     # eax = t
11897     8b/-> *(ebp+8) 0/r32/eax
11898     # if t is 'byte', size is 1
11899     3d/compare-eax-and 8/imm32/byte
11900     {
11901       75/jump-if-!= break/disp8
11902       b8/copy-to-eax 1/imm32
11903       eb/jump $array-element-size:end/disp8
11904     }
11905     # otherwise proceed as usual
11906     (size-of-type-id %eax)  # => eax
11907 $size-of-type-id-as-array-element:end:
11908     # . epilogue
11909     89/<- %esp 5/r32/ebp
11910     5d/pop-to-ebp
11911     c3/return
11912 
11913 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
11914     # . prologue
11915     55/push-ebp
11916     89/<- %ebp 4/r32/esp
11917     # . save registers
11918     50/push-eax
11919     53/push-ebx
11920     # ebx = base
11921     8b/-> *(ebp+0xc) 3/r32/ebx
11922     (emit-indent *(ebp+8) *Curr-block-depth)
11923     (write-buffered *(ebp+8) "8b/-> *")
11924     # if base is an (addr array ...) in a register
11925     {
11926       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
11927       74/jump-if-= break/disp8
11928 $emit-save-size-to:emit-base-from-register:
11929       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
11930       (write-buffered *(ebp+8) %eax)
11931       eb/jump $emit-save-size-to:emit-output/disp8
11932     }
11933     # otherwise if base is an (array ...) on the stack
11934     {
11935       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
11936       74/jump-if-= break/disp8
11937 $emit-save-size-to:emit-base-from-stack:
11938       (write-buffered *(ebp+8) "(ebp+")
11939       (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
11940       (write-buffered *(ebp+8) ")")
11941     }
11942 $emit-save-size-to:emit-output:
11943     (write-buffered *(ebp+8) " ")
11944     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
11945     (print-int32-buffered *(ebp+8) *eax)
11946     (write-buffered *(ebp+8) "/r32\n")
11947 $emit-save-size-to:end:
11948     # . restore registers
11949     5b/pop-to-ebx
11950     58/pop-to-eax
11951     # . epilogue
11952     89/<- %esp 5/r32/ebp
11953     5d/pop-to-ebp
11954     c3/return
11955 
11956 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
11957     # . prologue
11958     55/push-ebp
11959     89/<- %ebp 4/r32/esp
11960     # . save registers
11961     50/push-eax
11962     #
11963     (emit-indent *(ebp+8) *Curr-block-depth)
11964     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
11965     (write-buffered *(ebp+8) *(ebp+0xc))
11966     (write-buffered *(ebp+8) Space)
11967     (num-shift-rights *(ebp+0x10))  # => eax
11968     (print-int32-buffered *(ebp+8) %eax)
11969     (write-buffered *(ebp+8) "/imm8\n")
11970 $emit-divide-by-shift-right:end:
11971     # . restore registers
11972     58/pop-to-eax
11973     # . epilogue
11974     89/<- %esp 5/r32/ebp
11975     5d/pop-to-ebp
11976     c3/return
11977 
11978 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11979     # . prologue
11980     55/push-ebp
11981     89/<- %ebp 4/r32/esp
11982     # . save registers
11983     51/push-ecx
11984     # ecx = stmt
11985     8b/-> *(ebp+0xc) 1/r32/ecx
11986     # var base/ecx: (addr var) = stmt->inouts[0]
11987     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11988     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11989     89/<- %ecx 0/r32/eax
11990     # if (var->register) do one thing
11991     {
11992       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
11993       74/jump-if-= break/disp8
11994       # TODO: ensure there's no dereference
11995       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11996       eb/jump $translate-mu-index-stmt:end/disp8
11997     }
11998     # if (var->offset) do a different thing
11999     {
12000       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
12001       74/jump-if-= break/disp8
12002       # TODO: ensure there's no dereference
12003       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12004       eb/jump $translate-mu-index-stmt:end/disp8
12005     }
12006 $translate-mu-index-stmt:end:
12007     # . restore registers
12008     59/pop-to-ecx
12009     # . epilogue
12010     89/<- %esp 5/r32/ebp
12011     5d/pop-to-ebp
12012     c3/return
12013 
12014 $translate-mu-index-stmt-with-array:error1:
12015     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
12016     (flush *(ebp+0x10))
12017     (stop *(ebp+0x14) 1)
12018     # never gets here
12019 
12020 $translate-mu-index-stmt-with-array:error2:
12021     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
12022     (flush *(ebp+0x10))
12023     (stop *(ebp+0x14) 1)
12024     # never gets here
12025 
12026 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
12027     # . prologue
12028     55/push-ebp
12029     89/<- %ebp 4/r32/esp
12030     # . save registers
12031     50/push-eax
12032     51/push-ecx
12033     52/push-edx
12034     53/push-ebx
12035     #
12036     (emit-indent *(ebp+8) *Curr-block-depth)
12037     (write-buffered *(ebp+8) "8d/copy-address *(")
12038     # TODO: ensure inouts[0] is in a register and not dereferenced
12039 $translate-mu-index-stmt-with-array-in-register:emit-base:
12040     # ecx = stmt
12041     8b/-> *(ebp+0xc) 1/r32/ecx
12042     # var base/ebx: (addr var) = inouts[0]
12043     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12044     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12045     89/<- %ebx 0/r32/eax
12046     # print base->register " + "
12047     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
12048     (write-buffered *(ebp+8) %eax)
12049     (write-buffered *(ebp+8) " + ")
12050     # var index/edx: (addr var) = inouts[1]
12051     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12052     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12053     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12054     89/<- %edx 0/r32/eax
12055     # if index->register
12056     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
12057     {
12058       0f 84/jump-if-= break/disp32
12059 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
12060       # if index is an int
12061       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12062       (is-simple-mu-type? %eax 1)  # int => eax
12063       3d/compare-eax-and 0/imm32/false
12064       {
12065         0f 84/jump-if-= break/disp32
12066 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
12067         # print index->register "<<" log2(array-element-size(base)) " + 4) "
12068         # . index->register "<<"
12069         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
12070         (write-buffered *(ebp+8) %eax)
12071         (write-buffered *(ebp+8) "<<")
12072         # . log2(array-element-size(base->type))
12073         # TODO: ensure size is a power of 2
12074         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
12075         (num-shift-rights %eax)  # => eax
12076         (print-int32-buffered *(ebp+8) %eax)
12077         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
12078       }
12079       # if index->type is any other atom, abort
12080       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12081       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
12082       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
12083       # if index has type (offset ...)
12084       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
12085       (is-simple-mu-type? %eax 7)  # => eax
12086       3d/compare-eax-and 0/imm32/false
12087       {
12088         0f 84/jump-if-= break/disp32
12089         # print index->register
12090 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
12091         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
12092         (write-buffered *(ebp+8) %eax)
12093       }
12094 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
12095       (write-buffered *(ebp+8) " + 4) ")
12096       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
12097     }
12098     # otherwise if index is a literal
12099     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12100     (is-simple-mu-type? %eax 0)  # => eax
12101     3d/compare-eax-and 0/imm32/false
12102     {
12103       0f 84/jump-if-= break/disp32
12104 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
12105       # var index-value/edx: int = parse-hex-int(index->name)
12106       (lookup *edx *(edx+4))  # Var-name Var-name => eax
12107       (parse-hex-int %eax)  # => eax
12108       89/<- %edx 0/r32/eax
12109       # offset = idx-value * array-element-size(base->type)
12110       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
12111       f7 4/subop/multiply-into-eax %edx  # clobbers edx
12112       # offset += 4 for array size
12113       05/add-to-eax 4/imm32
12114       # TODO: check edx for overflow
12115       # print offset
12116       (print-int32-buffered *(ebp+8) %eax)
12117       (write-buffered *(ebp+8) ") ")
12118       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
12119     }
12120     # otherwise abort
12121     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
12122 $translate-mu-index-stmt-with-array-in-register:emit-output:
12123     # outputs[0] "/r32"
12124     8b/-> *(ebp+0xc) 1/r32/ecx
12125     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12126     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12127     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12128     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
12129     (print-int32-buffered *(ebp+8) *eax)
12130     (write-buffered *(ebp+8) "/r32\n")
12131 $translate-mu-index-stmt-with-array-in-register:end:
12132     # . restore registers
12133     5b/pop-to-ebx
12134     5a/pop-to-edx
12135     59/pop-to-ecx
12136     58/pop-to-eax
12137     # . epilogue
12138     89/<- %esp 5/r32/ebp
12139     5d/pop-to-ebp
12140     c3/return
12141 
12142 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
12143     # . prologue
12144     55/push-ebp
12145     89/<- %ebp 4/r32/esp
12146     # . save registers
12147     50/push-eax
12148     51/push-ecx
12149     52/push-edx
12150     53/push-ebx
12151     #
12152     (emit-indent *(ebp+8) *Curr-block-depth)
12153     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
12154     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
12155     8b/-> *(ebp+0xc) 0/r32/eax
12156     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12157     89/<- %edx 0/r32/eax
12158     # var base/ecx: (addr var) = lookup(curr->value)
12159     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12160     89/<- %ecx 0/r32/eax
12161     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
12162     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
12163     # var index/edx: (handle var) = curr2->value
12164     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12165     89/<- %edx 0/r32/eax
12166     # if index->register
12167     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
12168     {
12169       0f 84/jump-if-= break/disp32
12170 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
12171       # if index is an int
12172       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12173       (is-simple-mu-type? %eax 1)  # int => eax
12174       3d/compare-eax-and 0/imm32/false
12175       {
12176         0f 84/jump-if-= break/disp32
12177 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
12178         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
12179         # . inouts[1]->register "<<"
12180         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
12181         (write-buffered *(ebp+8) %eax)
12182         (write-buffered *(ebp+8) "<<")
12183         # . log2(array-element-size(base))
12184         # TODO: ensure size is a power of 2
12185         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
12186         (num-shift-rights %eax)  # => eax
12187         (print-int32-buffered *(ebp+8) %eax)
12188         #
12189         (write-buffered *(ebp+8) " + ")
12190         #
12191         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
12192         05/add-to-eax 4/imm32  # for array length
12193         (print-int32-buffered *(ebp+8) %eax)
12194         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
12195       }
12196       # if index->type is any other atom, abort
12197       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12198       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
12199       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
12200       # if index has type (offset ...)
12201       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
12202       (is-simple-mu-type? %eax 7)  # => eax
12203       3d/compare-eax-and 0/imm32/false
12204       {
12205         0f 84/jump-if-= break/disp32
12206         # print index->register
12207 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
12208         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
12209         (write-buffered *(ebp+8) %eax)
12210       }
12211 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
12212       (write-buffered *(ebp+8) ") ")
12213       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
12214     }
12215     # otherwise if index is a literal
12216     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
12217     (is-simple-mu-type? %eax 0)  # => eax
12218     3d/compare-eax-and 0/imm32/false
12219     {
12220       0f 84/jump-if-= break/disp32
12221 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
12222       # var idx-value/edx: int = parse-hex-int(index->name)
12223       (lookup *edx *(edx+4))  # Var-name Var-name => eax
12224       (parse-hex-int %eax)  # Var-name => eax
12225       89/<- %edx 0/r32/eax
12226       # offset = idx-value * array-element-size(base)
12227       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
12228       f7 4/subop/multiply-into-eax %edx  # clobbers edx
12229       # offset += base->offset
12230       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
12231       # offset += 4 for array size
12232       05/add-to-eax 4/imm32
12233       # TODO: check edx for overflow
12234       # print offset
12235       (print-int32-buffered *(ebp+8) %eax)
12236       (write-buffered *(ebp+8) ") ")
12237       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
12238     }
12239     # otherwise abort
12240     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
12241 $translate-mu-index-stmt-with-array-on-stack:emit-output:
12242     # outputs[0] "/r32"
12243     8b/-> *(ebp+0xc) 0/r32/eax
12244     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12245     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12246     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12247     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
12248     (print-int32-buffered *(ebp+8) *eax)
12249     (write-buffered *(ebp+8) "/r32\n")
12250 $translate-mu-index-stmt-with-array-on-stack:end:
12251     # . restore registers
12252     5b/pop-to-ebx
12253     5a/pop-to-edx
12254     59/pop-to-ecx
12255     58/pop-to-eax
12256     # . epilogue
12257     89/<- %esp 5/r32/ebp
12258     5d/pop-to-ebp
12259     c3/return
12260 
12261 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
12262     # . prologue
12263     55/push-ebp
12264     89/<- %ebp 4/r32/esp
12265     # . save registers
12266     50/push-eax
12267     51/push-ecx
12268     52/push-edx
12269     53/push-ebx
12270     #
12271     (emit-indent *(ebp+8) *Curr-block-depth)
12272     (write-buffered *(ebp+8) "69/multiply")
12273     # ecx = stmt
12274     8b/-> *(ebp+0xc) 1/r32/ecx
12275     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
12276     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12277     89/<- %ebx 0/r32/eax
12278 $translate-mu-compute-index-stmt:emit-index:
12279     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
12280     (emit-subx-var-as-rm32 *(ebp+8) %eax)
12281     (write-buffered *(ebp+8) Space)
12282 $translate-mu-compute-index-stmt:emit-elem-size:
12283     # var base/ebx: (addr var)
12284     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
12285     89/<- %ebx 0/r32/eax
12286     # print array-element-size(base)
12287     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
12288     (print-int32-buffered *(ebp+8) %eax)
12289     (write-buffered *(ebp+8) "/imm32 ")
12290 $translate-mu-compute-index-stmt:emit-output:
12291     # outputs[0] "/r32"
12292     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12293     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12294     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12295     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
12296     (print-int32-buffered *(ebp+8) *eax)
12297     (write-buffered *(ebp+8) "/r32\n")
12298 $translate-mu-compute-index-stmt:end:
12299     # . restore registers
12300     5b/pop-to-ebx
12301     5a/pop-to-edx
12302     59/pop-to-ecx
12303     58/pop-to-eax
12304     # . epilogue
12305     89/<- %esp 5/r32/ebp
12306     5d/pop-to-ebp
12307     c3/return
12308 
12309 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
12310     # . prologue
12311     55/push-ebp
12312     89/<- %ebp 4/r32/esp
12313     # . save registers
12314     50/push-eax
12315     51/push-ecx
12316     52/push-edx
12317     #
12318     (emit-indent *(ebp+8) *Curr-block-depth)
12319     (write-buffered *(ebp+8) "8d/copy-address ")
12320     # ecx = stmt
12321     8b/-> *(ebp+0xc) 1/r32/ecx
12322     # var offset/edx: int = get offset of stmt
12323     (mu-get-offset %ecx)  # => eax
12324     89/<- %edx 0/r32/eax
12325     # var base/eax: (addr var) = stmt->inouts->value
12326     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12327     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12328     # if base is in a register
12329     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
12330     {
12331       0f 84/jump-if-= break/disp32
12332 $translate-mu-get-stmt:emit-register-input:
12333       # emit "*(" base->register " + " offset ") "
12334       (write-buffered *(ebp+8) "*(")
12335       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12336       (write-buffered *(ebp+8) %eax)
12337       (write-buffered *(ebp+8) " + ")
12338       (print-int32-buffered *(ebp+8) %edx)
12339       (write-buffered *(ebp+8) ") ")
12340       e9/jump $translate-mu-get-stmt:emit-output/disp32
12341     }
12342     # otherwise base is on the stack
12343     {
12344 $translate-mu-get-stmt:emit-stack-input:
12345       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
12346       (write-buffered *(ebp+8) "*(ebp+")
12347       03/add *(eax+0x14) 2/r32/edx  # Var-offset
12348       (print-int32-buffered *(ebp+8) %edx)
12349       (write-buffered *(ebp+8) ") ")
12350       eb/jump $translate-mu-get-stmt:emit-output/disp8
12351     }
12352 $translate-mu-get-stmt:emit-output:
12353     # var output/eax: (addr var) = stmt->outputs->value
12354     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
12355     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12356     # emit offset->register "/r32"
12357     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
12358     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
12359     (print-int32-buffered *(ebp+8) *eax)
12360     (write-buffered *(ebp+8) "/r32\n")
12361 $translate-mu-get-stmt:end:
12362     # . restore registers
12363     5a/pop-to-edx
12364     59/pop-to-ecx
12365     58/pop-to-eax
12366     # . epilogue
12367     89/<- %esp 5/r32/ebp
12368     5d/pop-to-ebp
12369     c3/return
12370 
12371 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
12372     # precondition: n is positive
12373     # . prologue
12374     55/push-ebp
12375     89/<- %ebp 4/r32/esp
12376     #
12377     8b/-> *(ebp+8) 0/r32/eax
12378     # var t/eax: (addr tree type-id)
12379     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
12380     # if t == 0 abort
12381     3d/compare-eax-with 0/imm32
12382     0f 84/jump-if-== $array-element-type-id:error0/disp32
12383     # if t->is-atom? abort
12384     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
12385     0f 85/jump-if-!= $array-element-type-id:error1/disp32
12386     # if (t->left == addr) t = t->right
12387     {
12388       50/push-eax
12389       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
12390       (is-simple-mu-type? %eax 2)  # addr => eax
12391       3d/compare-eax-with 0/imm32/false
12392       58/pop-to-eax
12393       74/jump-if-= break/disp8
12394 $array-element-type-id:skip-addr:
12395       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
12396     }
12397     # if t == 0 abort
12398     3d/compare-eax-with 0/imm32
12399     0f 84/jump-if-= $array-element-type-id:error2/disp32
12400     # if t->is-atom? abort
12401     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
12402     0f 85/jump-if-!= $array-element-type-id:error2/disp32
12403     # if t->left != array abort
12404     {
12405       50/push-eax
12406       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
12407       (is-simple-mu-type? %eax 3)  # array => eax
12408       3d/compare-eax-with 0/imm32/false
12409       58/pop-to-eax
12410 $array-element-type-id:no-array:
12411       0f 84/jump-if-= $array-element-type-id:error2/disp32
12412     }
12413 $array-element-type-id:skip-array:
12414     # t = t->right
12415     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
12416     # if t == 0 abort
12417     3d/compare-eax-with 0/imm32
12418     0f 84/jump-if-= $array-element-type-id:error2/disp32
12419     # if t->is-atom? abort
12420     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
12421     0f 85/jump-if-!= $array-element-type-id:error2/disp32
12422     # return t->left->value
12423     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
12424     8b/-> *(eax+4) 0/r32/eax  # Tree-value
12425 $array-element-type-id:end:
12426     # . epilogue
12427     89/<- %esp 5/r32/ebp
12428     5d/pop-to-ebp
12429     c3/return
12430 
12431 $array-element-type-id:error0:
12432     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
12433     50/push-eax
12434     8b/-> *(ebp+8) 0/r32/eax
12435     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12436     (write-buffered *(ebp+0xc) %eax)
12437     58/pop-to-eax
12438     (write-buffered *(ebp+0xc) "' has no type\n")
12439     (flush *(ebp+0xc))
12440     (stop *(ebp+0x10) 1)
12441     # never gets here
12442 
12443 $array-element-type-id:error1:
12444     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
12445     50/push-eax
12446     8b/-> *(ebp+8) 0/r32/eax
12447     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12448     (write-buffered *(ebp+0xc) %eax)
12449     58/pop-to-eax
12450     (write-buffered *(ebp+0xc) "' has atomic type ")
12451     (print-int32-buffered *(ebp+0xc) *(eax+4))  # Tree-value
12452     (write-buffered *(ebp+0xc) Newline)
12453     (flush *(ebp+0xc))
12454     (stop *(ebp+0x10) 1)
12455     # never gets here
12456 
12457 $array-element-type-id:error2:
12458     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
12459     50/push-eax
12460     8b/-> *(ebp+8) 0/r32/eax
12461     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12462     (write-buffered *(ebp+0xc) %eax)
12463     58/pop-to-eax
12464     (write-buffered *(ebp+0xc) "' has non-array type\n")
12465     (flush *(ebp+0xc))
12466     (stop *(ebp+0x10) 1)
12467     # never gets here
12468 
12469 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
12470     # precondition: n is positive
12471     # . prologue
12472     55/push-ebp
12473     89/<- %ebp 4/r32/esp
12474     # eax = n
12475     8b/-> *(ebp+8) 0/r32/eax
12476     # if (n < 0) abort
12477     3d/compare-eax-with 0/imm32
12478     0f 8c/jump-if-< $power-of-2?:abort/disp32
12479     # var tmp/eax: int = n-1
12480     48/decrement-eax
12481     # var tmp2/eax: int = n & tmp
12482     23/and-> *(ebp+8) 0/r32/eax
12483     # return (tmp2 == 0)
12484     3d/compare-eax-and 0/imm32
12485     0f 94/set-byte-if-= %al
12486     81 4/subop/and %eax 0xff/imm32
12487 $power-of-2?:end:
12488     # . epilogue
12489     89/<- %esp 5/r32/ebp
12490     5d/pop-to-ebp
12491     c3/return
12492 
12493 $power-of-2?:abort:
12494     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
12495     (flush *(ebp+0xc))
12496     (stop *(ebp+0x10) 1)
12497     # never gets here
12498 
12499 num-shift-rights:  # n: int -> result/eax: int
12500     # precondition: n is a positive power of 2
12501     # . prologue
12502     55/push-ebp
12503     89/<- %ebp 4/r32/esp
12504     # . save registers
12505     51/push-ecx
12506     # var curr/ecx: int = n
12507     8b/-> *(ebp+8) 1/r32/ecx
12508     # result = 0
12509     b8/copy-to-eax 0/imm32
12510     {
12511       # if (curr <= 1) break
12512       81 7/subop/compare %ecx 1/imm32
12513       7e/jump-if-<= break/disp8
12514       40/increment-eax
12515       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
12516       eb/jump loop/disp8
12517     }
12518 $num-shift-rights:end:
12519     # . restore registers
12520     59/pop-to-ecx
12521     # . epilogue
12522     89/<- %esp 5/r32/ebp
12523     5d/pop-to-ebp
12524     c3/return
12525 
12526 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
12527     # . prologue
12528     55/push-ebp
12529     89/<- %ebp 4/r32/esp
12530     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
12531     8b/-> *(ebp+8) 0/r32/eax
12532     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12533     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
12534     # var output-var/eax: (addr var) = second-inout->value
12535     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12536 #?     (write-buffered Stderr "mu-get-offset: ")
12537 #?     (print-int32-buffered Stderr %eax)
12538 #?     (write-buffered Stderr " name: ")
12539 #?     50/push-eax
12540 #?     (lookup *eax *(eax+4))  # Var-name
12541 #?     (write-buffered Stderr %eax)
12542 #?     58/pop-to-eax
12543 #?     (write-buffered Stderr Newline)
12544 #?     (flush Stderr)
12545     # return output-var->stack-offset
12546     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
12547 #?     (write-buffered Stderr "=> ")
12548 #?     (print-int32-buffered Stderr %eax)
12549 #?     (write-buffered Stderr Newline)
12550 #?     (flush Stderr)
12551 $emit-get-offset:end:
12552     # . epilogue
12553     89/<- %esp 5/r32/ebp
12554     5d/pop-to-ebp
12555     c3/return
12556 
12557 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)
12558     # . prologue
12559     55/push-ebp
12560     89/<- %ebp 4/r32/esp
12561     # . save registers
12562     50/push-eax
12563     51/push-ecx
12564     56/push-esi
12565     # esi = block
12566     8b/-> *(ebp+0xc) 6/r32/esi
12567     # block->var->block-depth = *Curr-block-depth
12568     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
12569     8b/-> *Curr-block-depth 1/r32/ecx
12570     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
12571     # var stmts/eax: (addr list stmt) = lookup(block->statements)
12572     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
12573     #
12574     {
12575 $emit-subx-block:check-empty:
12576       3d/compare-eax-and 0/imm32
12577       0f 84/jump-if-= break/disp32
12578       (emit-indent *(ebp+8) *Curr-block-depth)
12579       (write-buffered *(ebp+8) "{\n")
12580       # var v/ecx: (addr var) = lookup(block->var)
12581       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
12582       89/<- %ecx 0/r32/eax
12583       #
12584       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12585       (write-buffered *(ebp+8) %eax)
12586       (write-buffered *(ebp+8) ":loop:\n")
12587       ff 0/subop/increment *Curr-block-depth
12588       (push *(ebp+0x10) *(esi+0xc))  # Block-var
12589       (push *(ebp+0x10) *(esi+0x10))  # Block-var
12590       (push *(ebp+0x10) 0)  # false
12591       # emit block->statements
12592       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
12593       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
12594       (pop *(ebp+0x10))  # => eax
12595       (pop *(ebp+0x10))  # => eax
12596       (pop *(ebp+0x10))  # => eax
12597       ff 1/subop/decrement *Curr-block-depth
12598       (emit-indent *(ebp+8) *Curr-block-depth)
12599       (write-buffered *(ebp+8) "}\n")
12600       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
12601       (write-buffered *(ebp+8) %eax)
12602       (write-buffered *(ebp+8) ":break:\n")
12603     }
12604 $emit-subx-block:end:
12605     # . restore registers
12606     5e/pop-to-esi
12607     59/pop-to-ecx
12608     58/pop-to-eax
12609     # . epilogue
12610     89/<- %esp 5/r32/ebp
12611     5d/pop-to-ebp
12612     c3/return
12613 
12614 # Primitives supported
12615 # See mu_instructions for a summary of this linked-list data structure.
12616 #
12617 # For each operation, put variants with hard-coded registers before flexible ones.
12618 #
12619 # Unfortunately, our restrictions on addresses require that various fields in
12620 # primitives be handles, which complicates these definitions.
12621 #   - we need to insert dummy fields all over the place for fake alloc-ids
12622 #   - we can't use our syntax sugar of quoted literals for string fields
12623 #
12624 # Fake alloc-ids are needed because our type definitions up top require
12625 # handles but it's clearer to statically allocate these long-lived objects.
12626 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
12627 #
12628 # Every 'object' below starts with a fake alloc-id. It may also contain other
12629 # fake alloc-ids for various handle fields.
12630 #
12631 # I think of objects starting with a fake alloc-id as having type 'payload'.
12632 # It's not really intended to be created dynamically; for that use `allocate`
12633 # as usual.
12634 #
12635 # Idea for a notation to simplify such definitions:
12636 #   _Primitive-increment-eax:  # (payload primitive)
12637 #     0x11/alloc-id:fake:payload
12638 #     0x11 @(0x11 "increment")  # name
12639 #     0 0                       # inouts
12640 #     0x11 @(0x11/payload
12641 #            0x11 @(0x11/payload  # List-value
12642 #                   0 0             # Var-name
12643 #                   0x11 @(0x11     # Var-type
12644 #                          1/is-atom
12645 #                          1/value 0/unused   # Tree-left
12646 #                          0 0                # Tree-right
12647 #                         )
12648 #                   1               # block-depth
12649 #                   0               # stack-offset
12650 #                   0x11 @(0x11 "eax")  # Var-register
12651 #                  )
12652 #            0 0)                 # List-next
12653 #     ...
12654 #     _Primitive-increment-ecx/imm32/next
12655 #   ...
12656 # Awfully complex and non-obvious. But also clearly signals there's something
12657 # to learn here, so may be worth trying.
12658 #
12659 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
12660 #
12661 # For now we'll continue to just use comments and manually ensure they stay up
12662 # to date.
12663 == data
12664 Primitives:  # (addr primitive)
12665 # - increment/decrement
12666 _Primitive-increment-eax:  # (addr primitive)
12667     # var/eax <- increment => 40/increment-eax
12668     0x11/imm32/alloc-id:fake
12669     _string-increment/imm32/name
12670     0/imm32/no-inouts
12671     0/imm32/no-inouts
12672     0x11/imm32/alloc-id:fake
12673     Single-int-var-in-eax/imm32/outputs
12674     0x11/imm32/alloc-id:fake
12675     _string_40_increment_eax/imm32/subx-name
12676     0/imm32/no-rm32
12677     0/imm32/no-r32
12678     0/imm32/no-imm32
12679     0/imm32/no-disp32
12680     0/imm32/output-is-write-only
12681     0x11/imm32/alloc-id:fake
12682     _Primitive-increment-ecx/imm32/next
12683 _Primitive-increment-ecx:  # (payload primitive)
12684     0x11/imm32/alloc-id:fake:payload
12685     # var/ecx <- increment => 41/increment-ecx
12686     0x11/imm32/alloc-id:fake
12687     _string-increment/imm32/name
12688     0/imm32/no-inouts
12689     0/imm32/no-inouts
12690     0x11/imm32/alloc-id:fake
12691     Single-int-var-in-ecx/imm32/outputs
12692     0x11/imm32/alloc-id:fake
12693     _string_41_increment_ecx/imm32/subx-name
12694     0/imm32/no-rm32
12695     0/imm32/no-r32
12696     0/imm32/no-imm32
12697     0/imm32/no-disp32
12698     0/imm32/output-is-write-only
12699     0x11/imm32/alloc-id:fake
12700     _Primitive-increment-edx/imm32/next
12701 _Primitive-increment-edx:  # (payload primitive)
12702     0x11/imm32/alloc-id:fake:payload
12703     # var/edx <- increment => 42/increment-edx
12704     0x11/imm32/alloc-id:fake
12705     _string-increment/imm32/name
12706     0/imm32/no-inouts
12707     0/imm32/no-inouts
12708     0x11/imm32/alloc-id:fake
12709     Single-int-var-in-edx/imm32/outputs
12710     0x11/imm32/alloc-id:fake
12711     _string_42_increment_edx/imm32/subx-name
12712     0/imm32/no-rm32
12713     0/imm32/no-r32
12714     0/imm32/no-imm32
12715     0/imm32/no-disp32
12716     0/imm32/output-is-write-only
12717     0x11/imm32/alloc-id:fake
12718     _Primitive-increment-ebx/imm32/next
12719 _Primitive-increment-ebx:  # (payload primitive)
12720     0x11/imm32/alloc-id:fake:payload
12721     # var/ebx <- increment => 43/increment-ebx
12722     0x11/imm32/alloc-id:fake
12723     _string-increment/imm32/name
12724     0/imm32/no-inouts
12725     0/imm32/no-inouts
12726     0x11/imm32/alloc-id:fake
12727     Single-int-var-in-ebx/imm32/outputs
12728     0x11/imm32/alloc-id:fake
12729     _string_43_increment_ebx/imm32/subx-name
12730     0/imm32/no-rm32
12731     0/imm32/no-r32
12732     0/imm32/no-imm32
12733     0/imm32/no-disp32
12734     0/imm32/output-is-write-only
12735     0x11/imm32/alloc-id:fake
12736     _Primitive-increment-esi/imm32/next
12737 _Primitive-increment-esi:  # (payload primitive)
12738     0x11/imm32/alloc-id:fake:payload
12739     # var/esi <- increment => 46/increment-esi
12740     0x11/imm32/alloc-id:fake
12741     _string-increment/imm32/name
12742     0/imm32/no-inouts
12743     0/imm32/no-inouts
12744     0x11/imm32/alloc-id:fake
12745     Single-int-var-in-esi/imm32/outputs
12746     0x11/imm32/alloc-id:fake
12747     _string_46_increment_esi/imm32/subx-name
12748     0/imm32/no-rm32
12749     0/imm32/no-r32
12750     0/imm32/no-imm32
12751     0/imm32/no-disp32
12752     0/imm32/output-is-write-only
12753     0x11/imm32/alloc-id:fake
12754     _Primitive-increment-edi/imm32/next
12755 _Primitive-increment-edi:  # (payload primitive)
12756     0x11/imm32/alloc-id:fake:payload
12757     # var/edi <- increment => 47/increment-edi
12758     0x11/imm32/alloc-id:fake
12759     _string-increment/imm32/name
12760     0/imm32/no-inouts
12761     0/imm32/no-inouts
12762     0x11/imm32/alloc-id:fake
12763     Single-int-var-in-edi/imm32/outputs
12764     0x11/imm32/alloc-id:fake
12765     _string_47_increment_edi/imm32/subx-name
12766     0/imm32/no-rm32
12767     0/imm32/no-r32
12768     0/imm32/no-imm32
12769     0/imm32/no-disp32
12770     0/imm32/output-is-write-only
12771     0x11/imm32/alloc-id:fake
12772     _Primitive-decrement-eax/imm32/next
12773 _Primitive-decrement-eax:  # (payload primitive)
12774     0x11/imm32/alloc-id:fake:payload
12775     # var/eax <- decrement => 48/decrement-eax
12776     0x11/imm32/alloc-id:fake
12777     _string-decrement/imm32/name
12778     0/imm32/no-inouts
12779     0/imm32/no-inouts
12780     0x11/imm32/alloc-id:fake
12781     Single-int-var-in-eax/imm32/outputs
12782     0x11/imm32/alloc-id:fake
12783     _string_48_decrement_eax/imm32/subx-name
12784     0/imm32/no-rm32
12785     0/imm32/no-r32
12786     0/imm32/no-imm32
12787     0/imm32/no-disp32
12788     0/imm32/output-is-write-only
12789     0x11/imm32/alloc-id:fake
12790     _Primitive-decrement-ecx/imm32/next
12791 _Primitive-decrement-ecx:  # (payload primitive)
12792     0x11/imm32/alloc-id:fake:payload
12793     # var/ecx <- decrement => 49/decrement-ecx
12794     0x11/imm32/alloc-id:fake
12795     _string-decrement/imm32/name
12796     0/imm32/no-inouts
12797     0/imm32/no-inouts
12798     0x11/imm32/alloc-id:fake
12799     Single-int-var-in-ecx/imm32/outputs
12800     0x11/imm32/alloc-id:fake
12801     _string_49_decrement_ecx/imm32/subx-name
12802     0/imm32/no-rm32
12803     0/imm32/no-r32
12804     0/imm32/no-imm32
12805     0/imm32/no-disp32
12806     0/imm32/output-is-write-only
12807     0x11/imm32/alloc-id:fake
12808     _Primitive-decrement-edx/imm32/next
12809 _Primitive-decrement-edx:  # (payload primitive)
12810     0x11/imm32/alloc-id:fake:payload
12811     # var/edx <- decrement => 4a/decrement-edx
12812     0x11/imm32/alloc-id:fake
12813     _string-decrement/imm32/name
12814     0/imm32/no-inouts
12815     0/imm32/no-inouts
12816     0x11/imm32/alloc-id:fake
12817     Single-int-var-in-edx/imm32/outputs
12818     0x11/imm32/alloc-id:fake
12819     _string_4a_decrement_edx/imm32/subx-name
12820     0/imm32/no-rm32
12821     0/imm32/no-r32
12822     0/imm32/no-imm32
12823     0/imm32/no-disp32
12824     0/imm32/output-is-write-only
12825     0x11/imm32/alloc-id:fake
12826     _Primitive-decrement-ebx/imm32/next
12827 _Primitive-decrement-ebx:  # (payload primitive)
12828     0x11/imm32/alloc-id:fake:payload
12829     # var/ebx <- decrement => 4b/decrement-ebx
12830     0x11/imm32/alloc-id:fake
12831     _string-decrement/imm32/name
12832     0/imm32/no-inouts
12833     0/imm32/no-inouts
12834     0x11/imm32/alloc-id:fake
12835     Single-int-var-in-ebx/imm32/outputs
12836     0x11/imm32/alloc-id:fake
12837     _string_4b_decrement_ebx/imm32/subx-name
12838     0/imm32/no-rm32
12839     0/imm32/no-r32
12840     0/imm32/no-imm32
12841     0/imm32/no-disp32
12842     0/imm32/output-is-write-only
12843     0x11/imm32/alloc-id:fake
12844     _Primitive-decrement-esi/imm32/next
12845 _Primitive-decrement-esi:  # (payload primitive)
12846     0x11/imm32/alloc-id:fake:payload
12847     # var/esi <- decrement => 4e/decrement-esi
12848     0x11/imm32/alloc-id:fake
12849     _string-decrement/imm32/name
12850     0/imm32/no-inouts
12851     0/imm32/no-inouts
12852     0x11/imm32/alloc-id:fake
12853     Single-int-var-in-esi/imm32/outputs
12854     0x11/imm32/alloc-id:fake
12855     _string_4e_decrement_esi/imm32/subx-name
12856     0/imm32/no-rm32
12857     0/imm32/no-r32
12858     0/imm32/no-imm32
12859     0/imm32/no-disp32
12860     0/imm32/output-is-write-only
12861     0x11/imm32/alloc-id:fake
12862     _Primitive-decrement-edi/imm32/next
12863 _Primitive-decrement-edi:  # (payload primitive)
12864     0x11/imm32/alloc-id:fake:payload
12865     # var/edi <- decrement => 4f/decrement-edi
12866     0x11/imm32/alloc-id:fake
12867     _string-decrement/imm32/name
12868     0/imm32/no-inouts
12869     0/imm32/no-inouts
12870     0x11/imm32/alloc-id:fake
12871     Single-int-var-in-edi/imm32/outputs
12872     0x11/imm32/alloc-id:fake
12873     _string_4f_decrement_edi/imm32/subx-name
12874     0/imm32/no-rm32
12875     0/imm32/no-r32
12876     0/imm32/no-imm32
12877     0/imm32/no-disp32
12878     0/imm32/output-is-write-only
12879     0x11/imm32/alloc-id:fake
12880     _Primitive-increment-mem/imm32/next
12881 _Primitive-increment-mem:  # (payload primitive)
12882     0x11/imm32/alloc-id:fake:payload
12883     # increment var => ff 0/subop/increment *(ebp+__)
12884     0x11/imm32/alloc-id:fake
12885     _string-increment/imm32/name
12886     0x11/imm32/alloc-id:fake
12887     Single-int-var-in-mem/imm32/inouts
12888     0/imm32/no-outputs
12889     0/imm32/no-outputs
12890     0x11/imm32/alloc-id:fake
12891     _string_ff_subop_increment/imm32/subx-name
12892     1/imm32/rm32-is-first-inout
12893     0/imm32/no-r32
12894     0/imm32/no-imm32
12895     0/imm32/no-disp32
12896     0/imm32/output-is-write-only
12897     0x11/imm32/alloc-id:fake
12898     _Primitive-increment-reg/imm32/next
12899 _Primitive-increment-reg:  # (payload primitive)
12900     0x11/imm32/alloc-id:fake:payload
12901     # var/reg <- increment => ff 0/subop/increment %__
12902     0x11/imm32/alloc-id:fake
12903     _string-increment/imm32/name
12904     0/imm32/no-inouts
12905     0/imm32/no-inouts
12906     0x11/imm32/alloc-id:fake
12907     Single-int-var-in-some-register/imm32/outputs
12908     0x11/imm32/alloc-id:fake
12909     _string_ff_subop_increment/imm32/subx-name
12910     3/imm32/rm32-is-first-output
12911     0/imm32/no-r32
12912     0/imm32/no-imm32
12913     0/imm32/no-disp32
12914     0/imm32/output-is-write-only
12915     0x11/imm32/alloc-id:fake
12916     _Primitive-decrement-mem/imm32/next
12917 _Primitive-decrement-mem:  # (payload primitive)
12918     0x11/imm32/alloc-id:fake:payload
12919     # decrement var => ff 1/subop/decrement *(ebp+__)
12920     0x11/imm32/alloc-id:fake
12921     _string-decrement/imm32/name
12922     0x11/imm32/alloc-id:fake
12923     Single-int-var-in-mem/imm32/inouts
12924     0/imm32/no-outputs
12925     0/imm32/no-outputs
12926     0x11/imm32/alloc-id:fake
12927     _string_ff_subop_decrement/imm32/subx-name
12928     1/imm32/rm32-is-first-inout
12929     0/imm32/no-r32
12930     0/imm32/no-imm32
12931     0/imm32/no-disp32
12932     0/imm32/output-is-write-only
12933     0x11/imm32/alloc-id:fake
12934     _Primitive-decrement-reg/imm32/next
12935 _Primitive-decrement-reg:  # (payload primitive)
12936     0x11/imm32/alloc-id:fake:payload
12937     # var/reg <- decrement => ff 1/subop/decrement %__
12938     0x11/imm32/alloc-id:fake
12939     _string-decrement/imm32/name
12940     0/imm32/no-inouts
12941     0/imm32/no-inouts
12942     0x11/imm32/alloc-id:fake
12943     Single-int-var-in-some-register/imm32/outputs
12944     0x11/imm32/alloc-id:fake
12945     _string_ff_subop_decrement/imm32/subx-name
12946     3/imm32/rm32-is-first-output
12947     0/imm32/no-r32
12948     0/imm32/no-imm32
12949     0/imm32/no-disp32
12950     0/imm32/output-is-write-only
12951     0x11/imm32/alloc-id:fake
12952     _Primitive-add-to-eax/imm32/next
12953 # - add
12954 _Primitive-add-to-eax:  # (payload primitive)
12955     0x11/imm32/alloc-id:fake:payload
12956     # var/eax <- add lit => 05/add-to-eax lit/imm32
12957     0x11/imm32/alloc-id:fake
12958     _string-add/imm32/name
12959     0x11/imm32/alloc-id:fake
12960     Single-lit-var/imm32/inouts
12961     0x11/imm32/alloc-id:fake
12962     Single-int-var-in-eax/imm32/outputs
12963     0x11/imm32/alloc-id:fake
12964     _string_05_add_to_eax/imm32/subx-name
12965     0/imm32/no-rm32
12966     0/imm32/no-r32
12967     1/imm32/imm32-is-first-inout
12968     0/imm32/no-disp32
12969     0/imm32/output-is-write-only
12970     0x11/imm32/alloc-id:fake
12971     _Primitive-add-reg-to-reg/imm32/next
12972 _Primitive-add-reg-to-reg:  # (payload primitive)
12973     0x11/imm32/alloc-id:fake:payload
12974     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
12975     0x11/imm32/alloc-id:fake
12976     _string-add/imm32/name
12977     0x11/imm32/alloc-id:fake
12978     Single-int-var-in-some-register/imm32/inouts
12979     0x11/imm32/alloc-id:fake
12980     Single-int-var-in-some-register/imm32/outputs
12981     0x11/imm32/alloc-id:fake
12982     _string_01_add_to/imm32/subx-name
12983     3/imm32/rm32-is-first-output
12984     1/imm32/r32-is-first-inout
12985     0/imm32/no-imm32
12986     0/imm32/no-disp32
12987     0/imm32/output-is-write-only
12988     0x11/imm32/alloc-id:fake
12989     _Primitive-add-reg-to-mem/imm32/next
12990 _Primitive-add-reg-to-mem:  # (payload primitive)
12991     0x11/imm32/alloc-id:fake:payload
12992     # add-to var1 var2/reg => 01/add-to var1 var2/r32
12993     0x11/imm32/alloc-id:fake
12994     _string-add-to/imm32/name
12995     0x11/imm32/alloc-id:fake
12996     Two-args-int-stack-int-reg/imm32/inouts
12997     0/imm32/no-outputs
12998     0/imm32/no-outputs
12999     0x11/imm32/alloc-id:fake
13000     _string_01_add_to/imm32/subx-name
13001     1/imm32/rm32-is-first-inout
13002     2/imm32/r32-is-second-inout
13003     0/imm32/no-imm32
13004     0/imm32/no-disp32
13005     0/imm32/output-is-write-only
13006     0x11/imm32/alloc-id:fake
13007     _Primitive-add-mem-to-reg/imm32/next
13008 _Primitive-add-mem-to-reg:  # (payload primitive)
13009     0x11/imm32/alloc-id:fake:payload
13010     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
13011     0x11/imm32/alloc-id:fake
13012     _string-add/imm32/name
13013     0x11/imm32/alloc-id:fake
13014     Single-int-var-in-mem/imm32/inouts
13015     0x11/imm32/alloc-id:fake
13016     Single-int-var-in-some-register/imm32/outputs
13017     0x11/imm32/alloc-id:fake
13018     _string_03_add/imm32/subx-name
13019     1/imm32/rm32-is-first-inout
13020     3/imm32/r32-is-first-output
13021     0/imm32/no-imm32
13022     0/imm32/no-disp32
13023     0/imm32/output-is-write-only
13024     0x11/imm32/alloc-id:fake
13025     _Primitive-add-lit-to-reg/imm32/next
13026 _Primitive-add-lit-to-reg:  # (payload primitive)
13027     0x11/imm32/alloc-id:fake:payload
13028     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
13029     0x11/imm32/alloc-id:fake
13030     _string-add/imm32/name
13031     0x11/imm32/alloc-id:fake
13032     Single-lit-var/imm32/inouts
13033     0x11/imm32/alloc-id:fake
13034     Single-int-var-in-some-register/imm32/outputs
13035     0x11/imm32/alloc-id:fake
13036     _string_81_subop_add/imm32/subx-name
13037     3/imm32/rm32-is-first-output
13038     0/imm32/no-r32
13039     1/imm32/imm32-is-first-inout
13040     0/imm32/no-disp32
13041     0/imm32/output-is-write-only
13042     0x11/imm32/alloc-id:fake
13043     _Primitive-add-lit-to-mem/imm32/next
13044 _Primitive-add-lit-to-mem:  # (payload primitive)
13045     0x11/imm32/alloc-id:fake:payload
13046     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
13047     0x11/imm32/alloc-id:fake
13048     _string-add-to/imm32/name
13049     0x11/imm32/alloc-id:fake
13050     Int-var-and-literal/imm32/inouts
13051     0/imm32/no-outputs
13052     0/imm32/no-outputs
13053     0x11/imm32/alloc-id:fake
13054     _string_81_subop_add/imm32/subx-name
13055     1/imm32/rm32-is-first-inout
13056     0/imm32/no-r32
13057     2/imm32/imm32-is-second-inout
13058     0/imm32/no-disp32
13059     0/imm32/output-is-write-only
13060     0x11/imm32/alloc-id:fake
13061     _Primitive-subtract-from-eax/imm32/next
13062 # - subtract
13063 _Primitive-subtract-from-eax:  # (payload primitive)
13064     0x11/imm32/alloc-id:fake:payload
13065     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
13066     0x11/imm32/alloc-id:fake
13067     _string-subtract/imm32/name
13068     0x11/imm32/alloc-id:fake
13069     Single-lit-var/imm32/inouts
13070     0x11/imm32/alloc-id:fake
13071     Single-int-var-in-eax/imm32/outputs
13072     0x11/imm32/alloc-id:fake
13073     _string_2d_subtract_from_eax/imm32/subx-name
13074     0/imm32/no-rm32
13075     0/imm32/no-r32
13076     1/imm32/imm32-is-first-inout
13077     0/imm32/no-disp32
13078     0/imm32/output-is-write-only
13079     0x11/imm32/alloc-id:fake
13080     _Primitive-subtract-reg-from-reg/imm32/next
13081 _Primitive-subtract-reg-from-reg:  # (payload primitive)
13082     0x11/imm32/alloc-id:fake:payload
13083     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
13084     0x11/imm32/alloc-id:fake
13085     _string-subtract/imm32/name
13086     0x11/imm32/alloc-id:fake
13087     Single-int-var-in-some-register/imm32/inouts
13088     0x11/imm32/alloc-id:fake
13089     Single-int-var-in-some-register/imm32/outputs
13090     0x11/imm32/alloc-id:fake
13091     _string_29_subtract_from/imm32/subx-name
13092     3/imm32/rm32-is-first-output
13093     1/imm32/r32-is-first-inout
13094     0/imm32/no-imm32
13095     0/imm32/no-disp32
13096     0/imm32/output-is-write-only
13097     0x11/imm32/alloc-id:fake
13098     _Primitive-subtract-reg-from-mem/imm32/next
13099 _Primitive-subtract-reg-from-mem:  # (payload primitive)
13100     0x11/imm32/alloc-id:fake:payload
13101     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
13102     0x11/imm32/alloc-id:fake
13103     _string-subtract-from/imm32/name
13104     0x11/imm32/alloc-id:fake
13105     Two-args-int-stack-int-reg/imm32/inouts
13106     0/imm32/no-outputs
13107     0/imm32/no-outputs
13108     0x11/imm32/alloc-id:fake
13109     _string_29_subtract_from/imm32/subx-name
13110     1/imm32/rm32-is-first-inout
13111     2/imm32/r32-is-second-inout
13112     0/imm32/no-imm32
13113     0/imm32/no-disp32
13114     0/imm32/output-is-write-only
13115     0x11/imm32/alloc-id:fake
13116     _Primitive-subtract-mem-from-reg/imm32/next
13117 _Primitive-subtract-mem-from-reg:  # (payload primitive)
13118     0x11/imm32/alloc-id:fake:payload
13119     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
13120     0x11/imm32/alloc-id:fake
13121     _string-subtract/imm32/name
13122     0x11/imm32/alloc-id:fake
13123     Single-int-var-in-mem/imm32/inouts
13124     0x11/imm32/alloc-id:fake
13125     Single-int-var-in-some-register/imm32/outputs
13126     0x11/imm32/alloc-id:fake
13127     _string_2b_subtract/imm32/subx-name
13128     1/imm32/rm32-is-first-inout
13129     3/imm32/r32-is-first-output
13130     0/imm32/no-imm32
13131     0/imm32/no-disp32
13132     0/imm32/output-is-write-only
13133     0x11/imm32/alloc-id:fake
13134     _Primitive-subtract-lit-from-reg/imm32/next
13135 _Primitive-subtract-lit-from-reg:  # (payload primitive)
13136     0x11/imm32/alloc-id:fake:payload
13137     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
13138     0x11/imm32/alloc-id:fake
13139     _string-subtract/imm32/name
13140     0x11/imm32/alloc-id:fake
13141     Single-lit-var/imm32/inouts
13142     0x11/imm32/alloc-id:fake
13143     Single-int-var-in-some-register/imm32/outputs
13144     0x11/imm32/alloc-id:fake
13145     _string_81_subop_subtract/imm32/subx-name
13146     3/imm32/rm32-is-first-output
13147     0/imm32/no-r32
13148     1/imm32/imm32-is-first-inout
13149     0/imm32/no-disp32
13150     0/imm32/output-is-write-only
13151     0x11/imm32/alloc-id:fake
13152     _Primitive-subtract-lit-from-mem/imm32/next
13153 _Primitive-subtract-lit-from-mem:  # (payload primitive)
13154     0x11/imm32/alloc-id:fake:payload
13155     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
13156     0x11/imm32/alloc-id:fake
13157     _string-subtract-from/imm32/name
13158     0x11/imm32/alloc-id:fake
13159     Int-var-and-literal/imm32/inouts
13160     0/imm32/no-outputs
13161     0/imm32/no-outputs
13162     0x11/imm32/alloc-id:fake
13163     _string_81_subop_subtract/imm32/subx-name
13164     1/imm32/rm32-is-first-inout
13165     0/imm32/no-r32
13166     2/imm32/imm32-is-first-inout
13167     0/imm32/no-disp32
13168     0/imm32/output-is-write-only
13169     0x11/imm32/alloc-id:fake
13170     _Primitive-and-with-eax/imm32/next
13171 # - and
13172 _Primitive-and-with-eax:  # (payload primitive)
13173     0x11/imm32/alloc-id:fake:payload
13174     # var/eax <- and lit => 25/and-with-eax lit/imm32
13175     0x11/imm32/alloc-id:fake
13176     _string-and/imm32/name
13177     0x11/imm32/alloc-id:fake
13178     Single-lit-var/imm32/inouts
13179     0x11/imm32/alloc-id:fake
13180     Single-int-var-in-eax/imm32/outputs
13181     0x11/imm32/alloc-id:fake
13182     _string_25_and_with_eax/imm32/subx-name
13183     0/imm32/no-rm32
13184     0/imm32/no-r32
13185     1/imm32/imm32-is-first-inout
13186     0/imm32/no-disp32
13187     0/imm32/output-is-write-only
13188     0x11/imm32/alloc-id:fake
13189     _Primitive-and-reg-with-reg/imm32/next
13190 _Primitive-and-reg-with-reg:  # (payload primitive)
13191     0x11/imm32/alloc-id:fake:payload
13192     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
13193     0x11/imm32/alloc-id:fake
13194     _string-and/imm32/name
13195     0x11/imm32/alloc-id:fake
13196     Single-int-var-in-some-register/imm32/inouts
13197     0x11/imm32/alloc-id:fake
13198     Single-int-var-in-some-register/imm32/outputs
13199     0x11/imm32/alloc-id:fake
13200     _string_21_and_with/imm32/subx-name
13201     3/imm32/rm32-is-first-output
13202     1/imm32/r32-is-first-inout
13203     0/imm32/no-imm32
13204     0/imm32/no-disp32
13205     0/imm32/output-is-write-only
13206     0x11/imm32/alloc-id:fake
13207     _Primitive-and-reg-with-mem/imm32/next
13208 _Primitive-and-reg-with-mem:  # (payload primitive)
13209     0x11/imm32/alloc-id:fake:payload
13210     # and-with var1 var2/reg => 21/and-with var1 var2/r32
13211     0x11/imm32/alloc-id:fake
13212     _string-and-with/imm32/name
13213     0x11/imm32/alloc-id:fake
13214     Two-args-int-stack-int-reg/imm32/inouts
13215     0/imm32/no-outputs
13216     0/imm32/no-outputs
13217     0x11/imm32/alloc-id:fake
13218     _string_21_and_with/imm32/subx-name
13219     1/imm32/rm32-is-first-inout
13220     2/imm32/r32-is-second-inout
13221     0/imm32/no-imm32
13222     0/imm32/no-disp32
13223     0/imm32/output-is-write-only
13224     0x11/imm32/alloc-id:fake
13225     _Primitive-and-mem-with-reg/imm32/next
13226 _Primitive-and-mem-with-reg:  # (payload primitive)
13227     0x11/imm32/alloc-id:fake:payload
13228     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
13229     0x11/imm32/alloc-id:fake
13230     _string-and/imm32/name
13231     0x11/imm32/alloc-id:fake
13232     Single-int-var-in-mem/imm32/inouts
13233     0x11/imm32/alloc-id:fake
13234     Single-int-var-in-some-register/imm32/outputs
13235     0x11/imm32/alloc-id:fake
13236     _string_23_and/imm32/subx-name
13237     1/imm32/rm32-is-first-inout
13238     3/imm32/r32-is-first-output
13239     0/imm32/no-imm32
13240     0/imm32/no-disp32
13241     0/imm32/output-is-write-only
13242     0x11/imm32/alloc-id:fake
13243     _Primitive-and-lit-with-reg/imm32/next
13244 _Primitive-and-lit-with-reg:  # (payload primitive)
13245     0x11/imm32/alloc-id:fake:payload
13246     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
13247     0x11/imm32/alloc-id:fake
13248     _string-and/imm32/name
13249     0x11/imm32/alloc-id:fake
13250     Single-lit-var/imm32/inouts
13251     0x11/imm32/alloc-id:fake
13252     Single-int-var-in-some-register/imm32/outputs
13253     0x11/imm32/alloc-id:fake
13254     _string_81_subop_and/imm32/subx-name
13255     3/imm32/rm32-is-first-output
13256     0/imm32/no-r32
13257     1/imm32/imm32-is-first-inout
13258     0/imm32/no-disp32
13259     0/imm32/output-is-write-only
13260     0x11/imm32/alloc-id:fake
13261     _Primitive-and-lit-with-mem/imm32/next
13262 _Primitive-and-lit-with-mem:  # (payload primitive)
13263     0x11/imm32/alloc-id:fake:payload
13264     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
13265     0x11/imm32/alloc-id:fake
13266     _string-and-with/imm32/name
13267     0x11/imm32/alloc-id:fake
13268     Int-var-and-literal/imm32/inouts
13269     0/imm32/no-outputs
13270     0/imm32/no-outputs
13271     0x11/imm32/alloc-id:fake
13272     _string_81_subop_and/imm32/subx-name
13273     1/imm32/rm32-is-first-inout
13274     0/imm32/no-r32
13275     2/imm32/imm32-is-first-inout
13276     0/imm32/no-disp32
13277     0/imm32/output-is-write-only
13278     0x11/imm32/alloc-id:fake
13279     _Primitive-or-with-eax/imm32/next
13280 # - or
13281 _Primitive-or-with-eax:  # (payload primitive)
13282     0x11/imm32/alloc-id:fake:payload
13283     # var/eax <- or lit => 0d/or-with-eax lit/imm32
13284     0x11/imm32/alloc-id:fake
13285     _string-or/imm32/name
13286     0x11/imm32/alloc-id:fake
13287     Single-lit-var/imm32/inouts
13288     0x11/imm32/alloc-id:fake
13289     Single-int-var-in-eax/imm32/outputs
13290     0x11/imm32/alloc-id:fake
13291     _string_0d_or_with_eax/imm32/subx-name
13292     0/imm32/no-rm32
13293     0/imm32/no-r32
13294     1/imm32/imm32-is-first-inout
13295     0/imm32/no-disp32
13296     0/imm32/output-is-write-only
13297     0x11/imm32/alloc-id:fake
13298     _Primitive-or-reg-with-reg/imm32/next
13299 _Primitive-or-reg-with-reg:  # (payload primitive)
13300     0x11/imm32/alloc-id:fake:payload
13301     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
13302     0x11/imm32/alloc-id:fake
13303     _string-or/imm32/name
13304     0x11/imm32/alloc-id:fake
13305     Single-int-var-in-some-register/imm32/inouts
13306     0x11/imm32/alloc-id:fake
13307     Single-int-var-in-some-register/imm32/outputs
13308     0x11/imm32/alloc-id:fake
13309     _string_09_or_with/imm32/subx-name
13310     3/imm32/rm32-is-first-output
13311     1/imm32/r32-is-first-inout
13312     0/imm32/no-imm32
13313     0/imm32/no-disp32
13314     0/imm32/output-is-write-only
13315     0x11/imm32/alloc-id:fake
13316     _Primitive-or-reg-with-mem/imm32/next
13317 _Primitive-or-reg-with-mem:  # (payload primitive)
13318     0x11/imm32/alloc-id:fake:payload
13319     # or-with var1 var2/reg => 09/or-with var1 var2/r32
13320     0x11/imm32/alloc-id:fake
13321     _string-or-with/imm32/name
13322     0x11/imm32/alloc-id:fake
13323     Two-args-int-stack-int-reg/imm32/inouts
13324     0/imm32/no-outputs
13325     0/imm32/no-outputs
13326     0x11/imm32/alloc-id:fake
13327     _string_09_or_with/imm32/subx-name
13328     1/imm32/rm32-is-first-inout
13329     2/imm32/r32-is-second-inout
13330     0/imm32/no-imm32
13331     0/imm32/no-disp32
13332     0/imm32/output-is-write-only
13333     0x11/imm32/alloc-id:fake
13334     _Primitive-or-mem-with-reg/imm32/next
13335 _Primitive-or-mem-with-reg:  # (payload primitive)
13336     0x11/imm32/alloc-id:fake:payload
13337     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
13338     0x11/imm32/alloc-id:fake
13339     _string-or/imm32/name
13340     0x11/imm32/alloc-id:fake
13341     Single-int-var-in-mem/imm32/inouts
13342     0x11/imm32/alloc-id:fake
13343     Single-int-var-in-some-register/imm32/outputs
13344     0x11/imm32/alloc-id:fake
13345     _string_0b_or/imm32/subx-name
13346     1/imm32/rm32-is-first-inout
13347     3/imm32/r32-is-first-output
13348     0/imm32/no-imm32
13349     0/imm32/no-disp32
13350     0/imm32/output-is-write-only
13351     0x11/imm32/alloc-id:fake
13352     _Primitive-or-lit-with-reg/imm32/next
13353 _Primitive-or-lit-with-reg:  # (payload primitive)
13354     0x11/imm32/alloc-id:fake:payload
13355     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
13356     0x11/imm32/alloc-id:fake
13357     _string-or/imm32/name
13358     0x11/imm32/alloc-id:fake
13359     Single-lit-var/imm32/inouts
13360     0x11/imm32/alloc-id:fake
13361     Single-int-var-in-some-register/imm32/outputs
13362     0x11/imm32/alloc-id:fake
13363     _string_81_subop_or/imm32/subx-name
13364     3/imm32/rm32-is-first-output
13365     0/imm32/no-r32
13366     1/imm32/imm32-is-first-inout
13367     0/imm32/no-disp32
13368     0/imm32/output-is-write-only
13369     0x11/imm32/alloc-id:fake
13370     _Primitive-or-lit-with-mem/imm32/next
13371 _Primitive-or-lit-with-mem:  # (payload primitive)
13372     0x11/imm32/alloc-id:fake:payload
13373     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
13374     0x11/imm32/alloc-id:fake
13375     _string-or-with/imm32/name
13376     0x11/imm32/alloc-id:fake
13377     Int-var-and-literal/imm32/inouts
13378     0/imm32/no-outputs
13379     0/imm32/no-outputs
13380     0x11/imm32/alloc-id:fake
13381     _string_81_subop_or/imm32/subx-name
13382     1/imm32/rm32-is-first-inout
13383     0/imm32/no-r32
13384     2/imm32/imm32-is-second-inout
13385     0/imm32/no-disp32
13386     0/imm32/output-is-write-only
13387     0x11/imm32/alloc-id:fake
13388     _Primitive-xor-with-eax/imm32/next
13389 # - xor
13390 _Primitive-xor-with-eax:  # (payload primitive)
13391     0x11/imm32/alloc-id:fake:payload
13392     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
13393     0x11/imm32/alloc-id:fake
13394     _string-xor/imm32/name
13395     0x11/imm32/alloc-id:fake
13396     Single-lit-var/imm32/inouts
13397     0x11/imm32/alloc-id:fake
13398     Single-int-var-in-eax/imm32/outputs
13399     0x11/imm32/alloc-id:fake
13400     _string_35_xor_with_eax/imm32/subx-name
13401     0/imm32/no-rm32
13402     0/imm32/no-r32
13403     1/imm32/imm32-is-first-inout
13404     0/imm32/no-disp32
13405     0/imm32/output-is-write-only
13406     0x11/imm32/alloc-id:fake
13407     _Primitive-xor-reg-with-reg/imm32/next
13408 _Primitive-xor-reg-with-reg:  # (payload primitive)
13409     0x11/imm32/alloc-id:fake:payload
13410     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
13411     0x11/imm32/alloc-id:fake
13412     _string-xor/imm32/name
13413     0x11/imm32/alloc-id:fake
13414     Single-int-var-in-some-register/imm32/inouts
13415     0x11/imm32/alloc-id:fake
13416     Single-int-var-in-some-register/imm32/outputs
13417     0x11/imm32/alloc-id:fake
13418     _string_31_xor_with/imm32/subx-name
13419     3/imm32/rm32-is-first-output
13420     1/imm32/r32-is-first-inout
13421     0/imm32/no-imm32
13422     0/imm32/no-disp32
13423     0/imm32/output-is-write-only
13424     0x11/imm32/alloc-id:fake
13425     _Primitive-xor-reg-with-mem/imm32/next
13426 _Primitive-xor-reg-with-mem:  # (payload primitive)
13427     0x11/imm32/alloc-id:fake:payload
13428     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
13429     0x11/imm32/alloc-id:fake
13430     _string-xor-with/imm32/name
13431     0x11/imm32/alloc-id:fake
13432     Two-args-int-stack-int-reg/imm32/inouts
13433     0/imm32/no-outputs
13434     0/imm32/no-outputs
13435     0x11/imm32/alloc-id:fake
13436     _string_31_xor_with/imm32/subx-name
13437     1/imm32/rm32-is-first-inout
13438     2/imm32/r32-is-second-inout
13439     0/imm32/no-imm32
13440     0/imm32/no-disp32
13441     0/imm32/output-is-write-only
13442     0x11/imm32/alloc-id:fake
13443     _Primitive-xor-mem-with-reg/imm32/next
13444 _Primitive-xor-mem-with-reg:  # (payload primitive)
13445     0x11/imm32/alloc-id:fake:payload
13446     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
13447     0x11/imm32/alloc-id:fake
13448     _string-xor/imm32/name
13449     0x11/imm32/alloc-id:fake
13450     Single-int-var-in-mem/imm32/inouts
13451     0x11/imm32/alloc-id:fake
13452     Single-int-var-in-some-register/imm32/outputs
13453     0x11/imm32/alloc-id:fake
13454     _string_33_xor/imm32/subx-name
13455     1/imm32/rm32-is-first-inout
13456     3/imm32/r32-is-first-output
13457     0/imm32/no-imm32
13458     0/imm32/no-disp32
13459     0/imm32/output-is-write-only
13460     0x11/imm32/alloc-id:fake
13461     _Primitive-xor-lit-with-reg/imm32/next
13462 _Primitive-xor-lit-with-reg:  # (payload primitive)
13463     0x11/imm32/alloc-id:fake:payload
13464     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
13465     0x11/imm32/alloc-id:fake
13466     _string-xor/imm32/name
13467     0x11/imm32/alloc-id:fake
13468     Single-lit-var/imm32/inouts
13469     0x11/imm32/alloc-id:fake
13470     Single-int-var-in-some-register/imm32/outputs
13471     0x11/imm32/alloc-id:fake
13472     _string_81_subop_xor/imm32/subx-name
13473     3/imm32/rm32-is-first-output
13474     0/imm32/no-r32
13475     1/imm32/imm32-is-first-inout
13476     0/imm32/no-disp32
13477     0/imm32/output-is-write-only
13478     0x11/imm32/alloc-id:fake
13479     _Primitive-xor-lit-with-mem/imm32/next
13480 _Primitive-xor-lit-with-mem:  # (payload primitive)
13481     0x11/imm32/alloc-id:fake:payload
13482     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
13483     0x11/imm32/alloc-id:fake
13484     _string-xor-with/imm32/name
13485     0x11/imm32/alloc-id:fake
13486     Int-var-and-literal/imm32/inouts
13487     0/imm32/no-outputs
13488     0/imm32/no-outputs
13489     0x11/imm32/alloc-id:fake
13490     _string_81_subop_xor/imm32/subx-name
13491     1/imm32/rm32-is-first-inout
13492     0/imm32/no-r32
13493     2/imm32/imm32-is-first-inout
13494     0/imm32/no-disp32
13495     0/imm32/output-is-write-only
13496     0x11/imm32/alloc-id:fake
13497     _Primitive-copy-to-eax/imm32/next
13498 # - copy
13499 _Primitive-copy-to-eax:  # (payload primitive)
13500     0x11/imm32/alloc-id:fake:payload
13501     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
13502     0x11/imm32/alloc-id:fake
13503     _string-copy/imm32/name
13504     0x11/imm32/alloc-id:fake
13505     Single-lit-var/imm32/inouts
13506     0x11/imm32/alloc-id:fake
13507     Single-int-var-in-eax/imm32/outputs
13508     0x11/imm32/alloc-id:fake
13509     _string_b8_copy_to_eax/imm32/subx-name
13510     0/imm32/no-rm32
13511     0/imm32/no-r32
13512     1/imm32/imm32-is-first-inout
13513     0/imm32/no-disp32
13514     1/imm32/output-is-write-only
13515     0x11/imm32/alloc-id:fake
13516     _Primitive-copy-to-ecx/imm32/next
13517 _Primitive-copy-to-ecx:  # (payload primitive)
13518     0x11/imm32/alloc-id:fake:payload
13519     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
13520     0x11/imm32/alloc-id:fake
13521     _string-copy/imm32/name
13522     0x11/imm32/alloc-id:fake
13523     Single-lit-var/imm32/inouts
13524     0x11/imm32/alloc-id:fake
13525     Single-int-var-in-ecx/imm32/outputs
13526     0x11/imm32/alloc-id:fake
13527     _string_b9_copy_to_ecx/imm32/subx-name
13528     0/imm32/no-rm32
13529     0/imm32/no-r32
13530     1/imm32/imm32-is-first-inout
13531     0/imm32/no-disp32
13532     1/imm32/output-is-write-only
13533     0x11/imm32/alloc-id:fake
13534     _Primitive-copy-to-edx/imm32/next
13535 _Primitive-copy-to-edx:  # (payload primitive)
13536     0x11/imm32/alloc-id:fake:payload
13537     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
13538     0x11/imm32/alloc-id:fake
13539     _string-copy/imm32/name
13540     0x11/imm32/alloc-id:fake
13541     Single-lit-var/imm32/inouts
13542     0x11/imm32/alloc-id:fake
13543     Single-int-var-in-edx/imm32/outputs
13544     0x11/imm32/alloc-id:fake
13545     _string_ba_copy_to_edx/imm32/subx-name
13546     0/imm32/no-rm32
13547     0/imm32/no-r32
13548     1/imm32/imm32-is-first-inout
13549     0/imm32/no-disp32
13550     1/imm32/output-is-write-only
13551     0x11/imm32/alloc-id:fake
13552     _Primitive-copy-to-ebx/imm32/next
13553 _Primitive-copy-to-ebx:  # (payload primitive)
13554     0x11/imm32/alloc-id:fake:payload
13555     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
13556     0x11/imm32/alloc-id:fake
13557     _string-copy/imm32/name
13558     0x11/imm32/alloc-id:fake
13559     Single-lit-var/imm32/inouts
13560     0x11/imm32/alloc-id:fake
13561     Single-int-var-in-ebx/imm32/outputs
13562     0x11/imm32/alloc-id:fake
13563     _string_bb_copy_to_ebx/imm32/subx-name
13564     0/imm32/no-rm32
13565     0/imm32/no-r32
13566     1/imm32/imm32-is-first-inout
13567     0/imm32/no-disp32
13568     1/imm32/output-is-write-only
13569     0x11/imm32/alloc-id:fake
13570     _Primitive-copy-to-esi/imm32/next
13571 _Primitive-copy-to-esi:  # (payload primitive)
13572     0x11/imm32/alloc-id:fake:payload
13573     # var/esi <- copy lit => be/copy-to-esi lit/imm32
13574     0x11/imm32/alloc-id:fake
13575     _string-copy/imm32/name
13576     0x11/imm32/alloc-id:fake
13577     Single-lit-var/imm32/inouts
13578     0x11/imm32/alloc-id:fake
13579     Single-int-var-in-esi/imm32/outputs
13580     0x11/imm32/alloc-id:fake
13581     _string_be_copy_to_esi/imm32/subx-name
13582     0/imm32/no-rm32
13583     0/imm32/no-r32
13584     1/imm32/imm32-is-first-inout
13585     0/imm32/no-disp32
13586     1/imm32/output-is-write-only
13587     0x11/imm32/alloc-id:fake
13588     _Primitive-copy-to-edi/imm32/next
13589 _Primitive-copy-to-edi:  # (payload primitive)
13590     0x11/imm32/alloc-id:fake:payload
13591     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
13592     0x11/imm32/alloc-id:fake
13593     _string-copy/imm32/name
13594     0x11/imm32/alloc-id:fake
13595     Single-lit-var/imm32/inouts
13596     0x11/imm32/alloc-id:fake
13597     Single-int-var-in-edi/imm32/outputs
13598     0x11/imm32/alloc-id:fake
13599     _string_bf_copy_to_edi/imm32/subx-name
13600     0/imm32/no-rm32
13601     0/imm32/no-r32
13602     1/imm32/imm32-is-first-inout
13603     0/imm32/no-disp32
13604     1/imm32/output-is-write-only
13605     0x11/imm32/alloc-id:fake
13606     _Primitive-copy-reg-to-reg/imm32/next
13607 _Primitive-copy-reg-to-reg:  # (payload primitive)
13608     0x11/imm32/alloc-id:fake:payload
13609     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
13610     0x11/imm32/alloc-id:fake
13611     _string-copy/imm32/name
13612     0x11/imm32/alloc-id:fake
13613     Single-int-var-in-some-register/imm32/inouts
13614     0x11/imm32/alloc-id:fake
13615     Single-int-var-in-some-register/imm32/outputs
13616     0x11/imm32/alloc-id:fake
13617     _string_89_<-/imm32/subx-name
13618     3/imm32/rm32-is-first-output
13619     1/imm32/r32-is-first-inout
13620     0/imm32/no-imm32
13621     0/imm32/no-disp32
13622     1/imm32/output-is-write-only
13623     0x11/imm32/alloc-id:fake
13624     _Primitive-copy-reg-to-mem/imm32/next
13625 _Primitive-copy-reg-to-mem:  # (payload primitive)
13626     0x11/imm32/alloc-id:fake:payload
13627     # copy-to var1 var2/reg => 89/<- var1 var2/r32
13628     0x11/imm32/alloc-id:fake
13629     _string-copy-to/imm32/name
13630     0x11/imm32/alloc-id:fake
13631     Two-args-int-stack-int-reg/imm32/inouts
13632     0/imm32/no-outputs
13633     0/imm32/no-outputs
13634     0x11/imm32/alloc-id:fake
13635     _string_89_<-/imm32/subx-name
13636     1/imm32/rm32-is-first-inout
13637     2/imm32/r32-is-second-inout
13638     0/imm32/no-imm32
13639     0/imm32/no-disp32
13640     1/imm32/output-is-write-only
13641     0x11/imm32/alloc-id:fake
13642     _Primitive-copy-mem-to-reg/imm32/next
13643 _Primitive-copy-mem-to-reg:  # (payload primitive)
13644     0x11/imm32/alloc-id:fake:payload
13645     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
13646     0x11/imm32/alloc-id:fake
13647     _string-copy/imm32/name
13648     0x11/imm32/alloc-id:fake
13649     Single-int-var-in-mem/imm32/inouts
13650     0x11/imm32/alloc-id:fake
13651     Single-int-var-in-some-register/imm32/outputs
13652     0x11/imm32/alloc-id:fake
13653     _string_8b_->/imm32/subx-name
13654     1/imm32/rm32-is-first-inout
13655     3/imm32/r32-is-first-output
13656     0/imm32/no-imm32
13657     0/imm32/no-disp32
13658     1/imm32/output-is-write-only
13659     0x11/imm32/alloc-id:fake
13660     _Primitive-copy-lit-to-reg/imm32/next
13661 _Primitive-copy-lit-to-reg:  # (payload primitive)
13662     0x11/imm32/alloc-id:fake:payload
13663     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
13664     0x11/imm32/alloc-id:fake
13665     _string-copy/imm32/name
13666     0x11/imm32/alloc-id:fake
13667     Single-lit-var/imm32/inouts
13668     0x11/imm32/alloc-id:fake
13669     Single-int-var-in-some-register/imm32/outputs
13670     0x11/imm32/alloc-id:fake
13671     _string_c7_subop_copy/imm32/subx-name
13672     3/imm32/rm32-is-first-output
13673     0/imm32/no-r32
13674     1/imm32/imm32-is-first-inout
13675     0/imm32/no-disp32
13676     1/imm32/output-is-write-only
13677     0x11/imm32/alloc-id:fake
13678     _Primitive-copy-lit-to-mem/imm32/next
13679 _Primitive-copy-lit-to-mem:  # (payload primitive)
13680     0x11/imm32/alloc-id:fake:payload
13681     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
13682     0x11/imm32/alloc-id:fake
13683     _string-copy-to/imm32/name
13684     0x11/imm32/alloc-id:fake
13685     Int-var-and-literal/imm32/inouts
13686     0/imm32/no-outputs
13687     0/imm32/no-outputs
13688     0x11/imm32/alloc-id:fake
13689     _string_c7_subop_copy/imm32/subx-name
13690     1/imm32/rm32-is-first-inout
13691     0/imm32/no-r32
13692     2/imm32/imm32-is-first-inout
13693     0/imm32/no-disp32
13694     1/imm32/output-is-write-only
13695     0x11/imm32/alloc-id:fake
13696     _Primitive-copy-byte-from-reg/imm32/next
13697 # - copy byte
13698 _Primitive-copy-byte-from-reg:
13699     0x11/imm32/alloc-id:fake:payload
13700     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
13701     0x11/imm32/alloc-id:fake
13702     _string-copy-byte/imm32/name
13703     0x11/imm32/alloc-id:fake
13704     Single-byte-var-in-some-register/imm32/inouts
13705     0x11/imm32/alloc-id:fake
13706     Single-byte-var-in-some-register/imm32/outputs
13707     0x11/imm32/alloc-id:fake
13708     _string_8a_copy_byte/imm32/subx-name
13709     1/imm32/rm32-is-first-inout
13710     3/imm32/r32-is-first-output
13711     0/imm32/no-imm32
13712     0/imm32/no-disp32
13713     1/imm32/output-is-write-only
13714     0x11/imm32/alloc-id:fake
13715     _Primitive-copy-byte-from-mem/imm32/next
13716 _Primitive-copy-byte-from-mem:
13717     0x11/imm32/alloc-id:fake:payload
13718     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
13719     0x11/imm32/alloc-id:fake
13720     _string-copy-byte/imm32/name
13721     0x11/imm32/alloc-id:fake
13722     Single-byte-var-in-mem/imm32/inouts
13723     0x11/imm32/alloc-id:fake
13724     Single-byte-var-in-some-register/imm32/outputs
13725     0x11/imm32/alloc-id:fake
13726     _string_8a_copy_byte/imm32/subx-name
13727     1/imm32/rm32-is-first-inout
13728     3/imm32/r32-is-first-output
13729     0/imm32/no-imm32
13730     0/imm32/no-disp32
13731     1/imm32/output-is-write-only
13732     0x11/imm32/alloc-id:fake
13733     _Primitive-copy-byte-to-mem/imm32/next
13734 _Primitive-copy-byte-to-mem:
13735     0x11/imm32/alloc-id:fake:payload
13736     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
13737     0x11/imm32/alloc-id:fake
13738     _string-copy-byte-to/imm32/name
13739     0x11/imm32/alloc-id:fake
13740     Two-args-byte-stack-byte-reg/imm32/inouts
13741     0/imm32/no-outputs
13742     0/imm32/no-outputs
13743     0x11/imm32/alloc-id:fake
13744     _string_88_copy_byte/imm32/subx-name
13745     1/imm32/rm32-is-first-inout
13746     2/imm32/r32-is-second-inout
13747     0/imm32/no-imm32
13748     0/imm32/no-disp32
13749     0/imm32/output-is-write-only
13750     0x11/imm32/alloc-id:fake
13751     _Primitive-address/imm32/next
13752 # - address
13753 _Primitive-address:  # (payload primitive)
13754     0x11/imm32/alloc-id:fake:payload
13755     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
13756     0x11/imm32/alloc-id:fake
13757     _string-address/imm32/name
13758     0x11/imm32/alloc-id:fake
13759     Single-int-var-in-mem/imm32/inouts
13760     0x11/imm32/alloc-id:fake
13761     Single-addr-var-in-some-register/imm32/outputs
13762     0x11/imm32/alloc-id:fake
13763     _string_8d_copy_address/imm32/subx-name
13764     1/imm32/rm32-is-first-inout
13765     3/imm32/r32-is-first-output
13766     0/imm32/no-imm32
13767     0/imm32/no-disp32
13768     1/imm32/output-is-write-only
13769     0x11/imm32/alloc-id:fake
13770     _Primitive-compare-reg-with-reg/imm32/next
13771 # - compare
13772 _Primitive-compare-reg-with-reg:  # (payload primitive)
13773     0x11/imm32/alloc-id:fake:payload
13774     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
13775     0x11/imm32/alloc-id:fake
13776     _string-compare/imm32/name
13777     0x11/imm32/alloc-id:fake
13778     Two-int-args-in-regs/imm32/inouts
13779     0/imm32/no-outputs
13780     0/imm32/no-outputs
13781     0x11/imm32/alloc-id:fake
13782     _string_39_compare->/imm32/subx-name
13783     1/imm32/rm32-is-first-inout
13784     2/imm32/r32-is-second-inout
13785     0/imm32/no-imm32
13786     0/imm32/no-disp32
13787     0/imm32/output-is-write-only
13788     0x11/imm32/alloc-id:fake
13789     _Primitive-compare-mem-with-reg/imm32/next
13790 _Primitive-compare-mem-with-reg:  # (payload primitive)
13791     0x11/imm32/alloc-id:fake:payload
13792     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
13793     0x11/imm32/alloc-id:fake
13794     _string-compare/imm32/name
13795     0x11/imm32/alloc-id:fake
13796     Two-args-int-stack-int-reg/imm32/inouts
13797     0/imm32/no-outputs
13798     0/imm32/no-outputs
13799     0x11/imm32/alloc-id:fake
13800     _string_39_compare->/imm32/subx-name
13801     1/imm32/rm32-is-first-inout
13802     2/imm32/r32-is-second-inout
13803     0/imm32/no-imm32
13804     0/imm32/no-disp32
13805     0/imm32/output-is-write-only
13806     0x11/imm32/alloc-id:fake
13807     _Primitive-compare-reg-with-mem/imm32/next
13808 _Primitive-compare-reg-with-mem:  # (payload primitive)
13809     0x11/imm32/alloc-id:fake:payload
13810     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
13811     0x11/imm32/alloc-id:fake
13812     _string-compare/imm32/name
13813     0x11/imm32/alloc-id:fake
13814     Two-args-int-reg-int-stack/imm32/inouts
13815     0/imm32/no-outputs
13816     0/imm32/no-outputs
13817     0x11/imm32/alloc-id:fake
13818     _string_3b_compare<-/imm32/subx-name
13819     2/imm32/rm32-is-second-inout
13820     1/imm32/r32-is-first-inout
13821     0/imm32/no-imm32
13822     0/imm32/no-disp32
13823     0/imm32/output-is-write-only
13824     0x11/imm32/alloc-id:fake
13825     _Primitive-compare-eax-with-literal/imm32/next
13826 _Primitive-compare-eax-with-literal:  # (payload primitive)
13827     0x11/imm32/alloc-id:fake:payload
13828     # compare var1/eax n => 3d/compare-eax-with n/imm32
13829     0x11/imm32/alloc-id:fake
13830     _string-compare/imm32/name
13831     0x11/imm32/alloc-id:fake
13832     Two-args-int-eax-int-literal/imm32/inouts
13833     0/imm32/no-outputs
13834     0/imm32/no-outputs
13835     0x11/imm32/alloc-id:fake
13836     _string_3d_compare_eax_with/imm32/subx-name
13837     0/imm32/no-rm32
13838     0/imm32/no-r32
13839     2/imm32/imm32-is-second-inout
13840     0/imm32/no-disp32
13841     0/imm32/output-is-write-only
13842     0x11/imm32/alloc-id:fake
13843     _Primitive-compare-reg-with-literal/imm32/next
13844 _Primitive-compare-reg-with-literal:  # (payload primitive)
13845     0x11/imm32/alloc-id:fake:payload
13846     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
13847     0x11/imm32/alloc-id:fake
13848     _string-compare/imm32/name
13849     0x11/imm32/alloc-id:fake
13850     Int-var-in-register-and-literal/imm32/inouts
13851     0/imm32/no-outputs
13852     0/imm32/no-outputs
13853     0x11/imm32/alloc-id:fake
13854     _string_81_subop_compare/imm32/subx-name
13855     1/imm32/rm32-is-first-inout
13856     0/imm32/no-r32
13857     2/imm32/imm32-is-second-inout
13858     0/imm32/no-disp32
13859     0/imm32/output-is-write-only
13860     0x11/imm32/alloc-id:fake
13861     _Primitive-compare-mem-with-literal/imm32/next
13862 _Primitive-compare-mem-with-literal:  # (payload primitive)
13863     0x11/imm32/alloc-id:fake:payload
13864     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
13865     0x11/imm32/alloc-id:fake
13866     _string-compare/imm32/name
13867     0x11/imm32/alloc-id:fake
13868     Int-var-and-literal/imm32/inouts
13869     0/imm32/no-outputs
13870     0/imm32/no-outputs
13871     0x11/imm32/alloc-id:fake
13872     _string_81_subop_compare/imm32/subx-name
13873     1/imm32/rm32-is-first-inout
13874     0/imm32/no-r32
13875     2/imm32/imm32-is-second-inout
13876     0/imm32/no-disp32
13877     0/imm32/output-is-write-only
13878     0x11/imm32/alloc-id:fake
13879     _Primitive-multiply-reg-by-reg/imm32/next
13880 # - multiply
13881 _Primitive-multiply-reg-by-reg:  # (payload primitive)
13882     0x11/imm32/alloc-id:fake:payload
13883     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
13884     0x11/imm32/alloc-id:fake
13885     _string-multiply/imm32/name
13886     0x11/imm32/alloc-id:fake
13887     Single-int-var-in-some-register/imm32/inouts
13888     0x11/imm32/alloc-id:fake
13889     Single-int-var-in-some-register/imm32/outputs
13890     0x11/imm32/alloc-id:fake
13891     _string_0f_af_multiply/imm32/subx-name
13892     1/imm32/rm32-is-first-inout
13893     3/imm32/r32-is-first-output
13894     0/imm32/no-imm32
13895     0/imm32/no-disp32
13896     0/imm32/output-is-write-only
13897     0x11/imm32/alloc-id:fake
13898     _Primitive-multiply-reg-by-mem/imm32/next
13899 _Primitive-multiply-reg-by-mem:  # (payload primitive)
13900     0x11/imm32/alloc-id:fake:payload
13901     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
13902     0x11/imm32/alloc-id:fake
13903     _string-multiply/imm32/name
13904     0x11/imm32/alloc-id:fake
13905     Single-int-var-in-mem/imm32/inouts
13906     0x11/imm32/alloc-id:fake
13907     Single-int-var-in-some-register/imm32/outputs
13908     0x11/imm32/alloc-id:fake
13909     _string_0f_af_multiply/imm32/subx-name
13910     1/imm32/rm32-is-first-inout
13911     3/imm32/r32-is-first-output
13912     0/imm32/no-imm32
13913     0/imm32/no-disp32
13914     0/imm32/output-is-write-only
13915     0x11/imm32/alloc-id:fake
13916     _Primitive-break-if-addr</imm32/next
13917 # - branches
13918 _Primitive-break-if-addr<:  # (payload primitive)
13919     0x11/imm32/alloc-id:fake:payload
13920     0x11/imm32/alloc-id:fake
13921     _string-break-if-addr</imm32/name
13922     0/imm32/no-inouts
13923     0/imm32/no-inouts
13924     0/imm32/no-outputs
13925     0/imm32/no-outputs
13926     0x11/imm32/alloc-id:fake
13927     _string_0f_82_jump_break/imm32/subx-name
13928     0/imm32/no-rm32
13929     0/imm32/no-r32
13930     0/imm32/no-imm32
13931     0/imm32/no-disp32
13932     0/imm32/no-output
13933     0x11/imm32/alloc-id:fake
13934     _Primitive-break-if-addr>=/imm32/next
13935 _Primitive-break-if-addr>=:  # (payload primitive)
13936     0x11/imm32/alloc-id:fake:payload
13937     0x11/imm32/alloc-id:fake
13938     _string-break-if-addr>=/imm32/name
13939     0/imm32/no-inouts
13940     0/imm32/no-inouts
13941     0/imm32/no-outputs
13942     0/imm32/no-outputs
13943     0x11/imm32/alloc-id:fake
13944     _string_0f_83_jump_break/imm32/subx-name
13945     0/imm32/no-rm32
13946     0/imm32/no-r32
13947     0/imm32/no-imm32
13948     0/imm32/no-disp32
13949     0/imm32/no-output
13950     0x11/imm32/alloc-id:fake
13951     _Primitive-break-if-=/imm32/next
13952 _Primitive-break-if-=:  # (payload primitive)
13953     0x11/imm32/alloc-id:fake:payload
13954     0x11/imm32/alloc-id:fake
13955     _string-break-if-=/imm32/name
13956     0/imm32/no-inouts
13957     0/imm32/no-inouts
13958     0/imm32/no-outputs
13959     0/imm32/no-outputs
13960     0x11/imm32/alloc-id:fake
13961     _string_0f_84_jump_break/imm32/subx-name
13962     0/imm32/no-rm32
13963     0/imm32/no-r32
13964     0/imm32/no-imm32
13965     0/imm32/no-disp32
13966     0/imm32/no-output
13967     0x11/imm32/alloc-id:fake
13968     _Primitive-break-if-!=/imm32/next
13969 _Primitive-break-if-!=:  # (payload primitive)
13970     0x11/imm32/alloc-id:fake:payload
13971     0x11/imm32/alloc-id:fake
13972     _string-break-if-!=/imm32/name
13973     0/imm32/no-inouts
13974     0/imm32/no-inouts
13975     0/imm32/no-outputs
13976     0/imm32/no-outputs
13977     0x11/imm32/alloc-id:fake
13978     _string_0f_85_jump_break/imm32/subx-name
13979     0/imm32/no-rm32
13980     0/imm32/no-r32
13981     0/imm32/no-imm32
13982     0/imm32/no-disp32
13983     0/imm32/no-output
13984     0x11/imm32/alloc-id:fake
13985     _Primitive-break-if-addr<=/imm32/next
13986 _Primitive-break-if-addr<=:  # (payload primitive)
13987     0x11/imm32/alloc-id:fake:payload
13988     0x11/imm32/alloc-id:fake
13989     _string-break-if-addr<=/imm32/name
13990     0/imm32/no-inouts
13991     0/imm32/no-inouts
13992     0/imm32/no-outputs
13993     0/imm32/no-outputs
13994     0x11/imm32/alloc-id:fake
13995     _string_0f_86_jump_break/imm32/subx-name
13996     0/imm32/no-rm32
13997     0/imm32/no-r32
13998     0/imm32/no-imm32
13999     0/imm32/no-disp32
14000     0/imm32/no-output
14001     0x11/imm32/alloc-id:fake
14002     _Primitive-break-if-addr>/imm32/next
14003 _Primitive-break-if-addr>:  # (payload primitive)
14004     0x11/imm32/alloc-id:fake:payload
14005     0x11/imm32/alloc-id:fake
14006     _string-break-if-addr>/imm32/name
14007     0/imm32/no-inouts
14008     0/imm32/no-inouts
14009     0/imm32/no-outputs
14010     0/imm32/no-outputs
14011     0x11/imm32/alloc-id:fake
14012     _string_0f_87_jump_break/imm32/subx-name
14013     0/imm32/no-rm32
14014     0/imm32/no-r32
14015     0/imm32/no-imm32
14016     0/imm32/no-disp32
14017     0/imm32/no-output
14018     0x11/imm32/alloc-id:fake
14019     _Primitive-break-if-</imm32/next
14020 _Primitive-break-if-<:  # (payload primitive)
14021     0x11/imm32/alloc-id:fake:payload
14022     0x11/imm32/alloc-id:fake
14023     _string-break-if-</imm32/name
14024     0/imm32/no-inouts
14025     0/imm32/no-inouts
14026     0/imm32/no-outputs
14027     0/imm32/no-outputs
14028     0x11/imm32/alloc-id:fake
14029     _string_0f_8c_jump_break/imm32/subx-name
14030     0/imm32/no-rm32
14031     0/imm32/no-r32
14032     0/imm32/no-imm32
14033     0/imm32/no-disp32
14034     0/imm32/no-output
14035     0x11/imm32/alloc-id:fake
14036     _Primitive-break-if->=/imm32/next
14037 _Primitive-break-if->=:  # (payload primitive)
14038     0x11/imm32/alloc-id:fake:payload
14039     0x11/imm32/alloc-id:fake
14040     _string-break-if->=/imm32/name
14041     0/imm32/no-inouts
14042     0/imm32/no-inouts
14043     0/imm32/no-outputs
14044     0/imm32/no-outputs
14045     0x11/imm32/alloc-id:fake
14046     _string_0f_8d_jump_break/imm32/subx-name
14047     0/imm32/no-rm32
14048     0/imm32/no-r32
14049     0/imm32/no-imm32
14050     0/imm32/no-disp32
14051     0/imm32/no-output
14052     0x11/imm32/alloc-id:fake
14053     _Primitive-break-if-<=/imm32/next
14054 _Primitive-break-if-<=:  # (payload primitive)
14055     0x11/imm32/alloc-id:fake:payload
14056     0x11/imm32/alloc-id:fake
14057     _string-break-if-<=/imm32/name
14058     0/imm32/no-inouts
14059     0/imm32/no-inouts
14060     0/imm32/no-outputs
14061     0/imm32/no-outputs
14062     0x11/imm32/alloc-id:fake
14063     _string_0f_8e_jump_break/imm32/subx-name
14064     0/imm32/no-rm32
14065     0/imm32/no-r32
14066     0/imm32/no-imm32
14067     0/imm32/no-disp32
14068     0/imm32/no-output
14069     0x11/imm32/alloc-id:fake
14070     _Primitive-break-if->/imm32/next
14071 _Primitive-break-if->:  # (payload primitive)
14072     0x11/imm32/alloc-id:fake:payload
14073     0x11/imm32/alloc-id:fake
14074     _string-break-if->/imm32/name
14075     0/imm32/no-inouts
14076     0/imm32/no-inouts
14077     0/imm32/no-outputs
14078     0/imm32/no-outputs
14079     0x11/imm32/alloc-id:fake
14080     _string_0f_8f_jump_break/imm32/subx-name
14081     0/imm32/no-rm32
14082     0/imm32/no-r32
14083     0/imm32/no-imm32
14084     0/imm32/no-disp32
14085     0/imm32/no-output
14086     0x11/imm32/alloc-id:fake
14087     _Primitive-break/imm32/next
14088 _Primitive-break:  # (payload primitive)
14089     0x11/imm32/alloc-id:fake:payload
14090     0x11/imm32/alloc-id:fake
14091     _string-break/imm32/name
14092     0/imm32/no-inouts
14093     0/imm32/no-inouts
14094     0/imm32/no-outputs
14095     0/imm32/no-outputs
14096     0x11/imm32/alloc-id:fake
14097     _string_e9_jump_break/imm32/subx-name
14098     0/imm32/no-rm32
14099     0/imm32/no-r32
14100     0/imm32/no-imm32
14101     0/imm32/no-disp32
14102     0/imm32/no-output
14103     0x11/imm32/alloc-id:fake
14104     _Primitive-loop-if-addr</imm32/next
14105 _Primitive-loop-if-addr<:  # (payload primitive)
14106     0x11/imm32/alloc-id:fake:payload
14107     0x11/imm32/alloc-id:fake
14108     _string-loop-if-addr</imm32/name
14109     0/imm32/no-inouts
14110     0/imm32/no-inouts
14111     0/imm32/no-outputs
14112     0/imm32/no-outputs
14113     0x11/imm32/alloc-id:fake
14114     _string_0f_82_jump_loop/imm32/subx-name
14115     0/imm32/no-rm32
14116     0/imm32/no-r32
14117     0/imm32/no-imm32
14118     0/imm32/no-disp32
14119     0/imm32/no-output
14120     0x11/imm32/alloc-id:fake
14121     _Primitive-loop-if-addr>=/imm32/next
14122 _Primitive-loop-if-addr>=:  # (payload primitive)
14123     0x11/imm32/alloc-id:fake:payload
14124     0x11/imm32/alloc-id:fake
14125     _string-loop-if-addr>=/imm32/name
14126     0/imm32/no-inouts
14127     0/imm32/no-inouts
14128     0/imm32/no-outputs
14129     0/imm32/no-outputs
14130     0x11/imm32/alloc-id:fake
14131     _string_0f_83_jump_loop/imm32/subx-name
14132     0/imm32/no-rm32
14133     0/imm32/no-r32
14134     0/imm32/no-imm32
14135     0/imm32/no-disp32
14136     0/imm32/no-output
14137     0x11/imm32/alloc-id:fake
14138     _Primitive-loop-if-=/imm32/next
14139 _Primitive-loop-if-=:  # (payload primitive)
14140     0x11/imm32/alloc-id:fake:payload
14141     0x11/imm32/alloc-id:fake
14142     _string-loop-if-=/imm32/name
14143     0/imm32/no-inouts
14144     0/imm32/no-inouts
14145     0/imm32/no-outputs
14146     0/imm32/no-outputs
14147     0x11/imm32/alloc-id:fake
14148     _string_0f_84_jump_loop/imm32/subx-name
14149     0/imm32/no-rm32
14150     0/imm32/no-r32
14151     0/imm32/no-imm32
14152     0/imm32/no-disp32
14153     0/imm32/no-output
14154     0x11/imm32/alloc-id:fake
14155     _Primitive-loop-if-!=/imm32/next
14156 _Primitive-loop-if-!=:  # (payload primitive)
14157     0x11/imm32/alloc-id:fake:payload
14158     0x11/imm32/alloc-id:fake
14159     _string-loop-if-!=/imm32/name
14160     0/imm32/no-inouts
14161     0/imm32/no-inouts
14162     0/imm32/no-outputs
14163     0/imm32/no-outputs
14164     0x11/imm32/alloc-id:fake
14165     _string_0f_85_jump_loop/imm32/subx-name
14166     0/imm32/no-rm32
14167     0/imm32/no-r32
14168     0/imm32/no-imm32
14169     0/imm32/no-disp32
14170     0/imm32/no-output
14171     0x11/imm32/alloc-id:fake
14172     _Primitive-loop-if-addr<=/imm32/next
14173 _Primitive-loop-if-addr<=:  # (payload primitive)
14174     0x11/imm32/alloc-id:fake:payload
14175     0x11/imm32/alloc-id:fake
14176     _string-loop-if-addr<=/imm32/name
14177     0/imm32/no-inouts
14178     0/imm32/no-inouts
14179     0/imm32/no-outputs
14180     0/imm32/no-outputs
14181     0x11/imm32/alloc-id:fake
14182     _string_0f_86_jump_loop/imm32/subx-name
14183     0/imm32/no-rm32
14184     0/imm32/no-r32
14185     0/imm32/no-imm32
14186     0/imm32/no-disp32
14187     0/imm32/no-output
14188     0x11/imm32/alloc-id:fake
14189     _Primitive-loop-if-addr>/imm32/next
14190 _Primitive-loop-if-addr>:  # (payload primitive)
14191     0x11/imm32/alloc-id:fake:payload
14192     0x11/imm32/alloc-id:fake
14193     _string-loop-if-addr>/imm32/name
14194     0/imm32/no-inouts
14195     0/imm32/no-inouts
14196     0/imm32/no-outputs
14197     0/imm32/no-outputs
14198     0x11/imm32/alloc-id:fake
14199     _string_0f_87_jump_loop/imm32/subx-name
14200     0/imm32/no-rm32
14201     0/imm32/no-r32
14202     0/imm32/no-imm32
14203     0/imm32/no-disp32
14204     0/imm32/no-output
14205     0x11/imm32/alloc-id:fake
14206     _Primitive-loop-if-</imm32/next
14207 _Primitive-loop-if-<:  # (payload primitive)
14208     0x11/imm32/alloc-id:fake:payload
14209     0x11/imm32/alloc-id:fake
14210     _string-loop-if-</imm32/name
14211     0/imm32/no-inouts
14212     0/imm32/no-inouts
14213     0/imm32/no-outputs
14214     0/imm32/no-outputs
14215     0x11/imm32/alloc-id:fake
14216     _string_0f_8c_jump_loop/imm32/subx-name
14217     0/imm32/no-rm32
14218     0/imm32/no-r32
14219     0/imm32/no-imm32
14220     0/imm32/no-disp32
14221     0/imm32/no-output
14222     0x11/imm32/alloc-id:fake
14223     _Primitive-loop-if->=/imm32/next
14224 _Primitive-loop-if->=:  # (payload primitive)
14225     0x11/imm32/alloc-id:fake:payload
14226     0x11/imm32/alloc-id:fake
14227     _string-loop-if->=/imm32/name
14228     0/imm32/no-inouts
14229     0/imm32/no-inouts
14230     0/imm32/no-outputs
14231     0/imm32/no-outputs
14232     0x11/imm32/alloc-id:fake
14233     _string_0f_8d_jump_loop/imm32/subx-name
14234     0/imm32/no-rm32
14235     0/imm32/no-r32
14236     0/imm32/no-imm32
14237     0/imm32/no-disp32
14238     0/imm32/no-output
14239     0x11/imm32/alloc-id:fake
14240     _Primitive-loop-if-<=/imm32/next
14241 _Primitive-loop-if-<=:  # (payload primitive)
14242     0x11/imm32/alloc-id:fake:payload
14243     0x11/imm32/alloc-id:fake
14244     _string-loop-if-<=/imm32/name
14245     0/imm32/no-inouts
14246     0/imm32/no-inouts
14247     0/imm32/no-outputs
14248     0/imm32/no-outputs
14249     0x11/imm32/alloc-id:fake
14250     _string_0f_8e_jump_loop/imm32/subx-name
14251     0/imm32/no-rm32
14252     0/imm32/no-r32
14253     0/imm32/no-imm32
14254     0/imm32/no-disp32
14255     0/imm32/no-output
14256     0x11/imm32/alloc-id:fake
14257     _Primitive-loop-if->/imm32/next
14258 _Primitive-loop-if->:  # (payload primitive)
14259     0x11/imm32/alloc-id:fake:payload
14260     0x11/imm32/alloc-id:fake
14261     _string-loop-if->/imm32/name
14262     0/imm32/no-inouts
14263     0/imm32/no-inouts
14264     0/imm32/no-outputs
14265     0/imm32/no-outputs
14266     0x11/imm32/alloc-id:fake
14267     _string_0f_8f_jump_loop/imm32/subx-name
14268     0/imm32/no-rm32
14269     0/imm32/no-r32
14270     0/imm32/no-imm32
14271     0/imm32/no-disp32
14272     0/imm32/no-output
14273     0x11/imm32/alloc-id:fake
14274     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
14275 _Primitive-loop:  # (payload primitive)
14276     0x11/imm32/alloc-id:fake:payload
14277     0x11/imm32/alloc-id:fake
14278     _string-loop/imm32/name
14279     0/imm32/no-inouts
14280     0/imm32/no-inouts
14281     0/imm32/no-outputs
14282     0/imm32/no-outputs
14283     0x11/imm32/alloc-id:fake
14284     _string_e9_jump_loop/imm32/subx-name
14285     0/imm32/no-rm32
14286     0/imm32/no-r32
14287     0/imm32/no-imm32
14288     0/imm32/no-disp32
14289     0/imm32/no-output
14290     0x11/imm32/alloc-id:fake
14291     _Primitive-break-if-addr<-named/imm32/next
14292 # - branches to named blocks
14293 _Primitive-break-if-addr<-named:  # (payload primitive)
14294     0x11/imm32/alloc-id:fake:payload
14295     0x11/imm32/alloc-id:fake
14296     _string-break-if-addr</imm32/name
14297     0x11/imm32/alloc-id:fake
14298     Single-lit-var/imm32/inouts
14299     0/imm32/no-outputs
14300     0/imm32/no-outputs
14301     0x11/imm32/alloc-id:fake
14302     _string_0f_82_jump_label/imm32/subx-name
14303     0/imm32/no-rm32
14304     0/imm32/no-r32
14305     0/imm32/no-imm32
14306     1/imm32/disp32-is-first-inout
14307     0/imm32/no-output
14308     0x11/imm32/alloc-id:fake
14309     _Primitive-break-if-addr>=-named/imm32/next
14310 _Primitive-break-if-addr>=-named:  # (payload primitive)
14311     0x11/imm32/alloc-id:fake:payload
14312     0x11/imm32/alloc-id:fake
14313     _string-break-if-addr>=/imm32/name
14314     0x11/imm32/alloc-id:fake
14315     Single-lit-var/imm32/inouts
14316     0/imm32/no-outputs
14317     0/imm32/no-outputs
14318     0x11/imm32/alloc-id:fake
14319     _string_0f_83_jump_label/imm32/subx-name
14320     0/imm32/no-rm32
14321     0/imm32/no-r32
14322     0/imm32/no-imm32
14323     1/imm32/disp32-is-first-inout
14324     0/imm32/no-output
14325     0x11/imm32/alloc-id:fake
14326     _Primitive-break-if-=-named/imm32/next
14327 _Primitive-break-if-=-named:  # (payload primitive)
14328     0x11/imm32/alloc-id:fake:payload
14329     0x11/imm32/alloc-id:fake
14330     _string-break-if-=/imm32/name
14331     0x11/imm32/alloc-id:fake
14332     Single-lit-var/imm32/inouts
14333     0/imm32/no-outputs
14334     0/imm32/no-outputs
14335     0x11/imm32/alloc-id:fake
14336     _string_0f_84_jump_label/imm32/subx-name
14337     0/imm32/no-rm32
14338     0/imm32/no-r32
14339     0/imm32/no-imm32
14340     1/imm32/disp32-is-first-inout
14341     0/imm32/no-output
14342     0x11/imm32/alloc-id:fake
14343     _Primitive-break-if-!=-named/imm32/next
14344 _Primitive-break-if-!=-named:  # (payload primitive)
14345     0x11/imm32/alloc-id:fake:payload
14346     0x11/imm32/alloc-id:fake
14347     _string-break-if-!=/imm32/name
14348     0x11/imm32/alloc-id:fake
14349     Single-lit-var/imm32/inouts
14350     0/imm32/no-outputs
14351     0/imm32/no-outputs
14352     0x11/imm32/alloc-id:fake
14353     _string_0f_85_jump_label/imm32/subx-name
14354     0/imm32/no-rm32
14355     0/imm32/no-r32
14356     0/imm32/no-imm32
14357     1/imm32/disp32-is-first-inout
14358     0/imm32/no-output
14359     0x11/imm32/alloc-id:fake
14360     _Primitive-break-if-addr<=-named/imm32/next
14361 _Primitive-break-if-addr<=-named:  # (payload primitive)
14362     0x11/imm32/alloc-id:fake:payload
14363     0x11/imm32/alloc-id:fake
14364     _string-break-if-addr<=/imm32/name
14365     0x11/imm32/alloc-id:fake
14366     Single-lit-var/imm32/inouts
14367     0/imm32/no-outputs
14368     0/imm32/no-outputs
14369     0x11/imm32/alloc-id:fake
14370     _string_0f_86_jump_label/imm32/subx-name
14371     0/imm32/no-rm32
14372     0/imm32/no-r32
14373     0/imm32/no-imm32
14374     1/imm32/disp32-is-first-inout
14375     0/imm32/no-output
14376     0x11/imm32/alloc-id:fake
14377     _Primitive-break-if-addr>-named/imm32/next
14378 _Primitive-break-if-addr>-named:  # (payload primitive)
14379     0x11/imm32/alloc-id:fake:payload
14380     0x11/imm32/alloc-id:fake
14381     _string-break-if-addr>/imm32/name
14382     0x11/imm32/alloc-id:fake
14383     Single-lit-var/imm32/inouts
14384     0/imm32/no-outputs
14385     0/imm32/no-outputs
14386     0x11/imm32/alloc-id:fake
14387     _string_0f_87_jump_label/imm32/subx-name
14388     0/imm32/no-rm32
14389     0/imm32/no-r32
14390     0/imm32/no-imm32
14391     1/imm32/disp32-is-first-inout
14392     0/imm32/no-output
14393     0x11/imm32/alloc-id:fake
14394     _Primitive-break-if-<-named/imm32/next
14395 _Primitive-break-if-<-named:  # (payload primitive)
14396     0x11/imm32/alloc-id:fake:payload
14397     0x11/imm32/alloc-id:fake
14398     _string-break-if-</imm32/name
14399     0x11/imm32/alloc-id:fake
14400     Single-lit-var/imm32/inouts
14401     0/imm32/no-outputs
14402     0/imm32/no-outputs
14403     0x11/imm32/alloc-id:fake
14404     _string_0f_8c_jump_label/imm32/subx-name
14405     0/imm32/no-rm32
14406     0/imm32/no-r32
14407     0/imm32/no-imm32
14408     1/imm32/disp32-is-first-inout
14409     0/imm32/no-output
14410     0x11/imm32/alloc-id:fake
14411     _Primitive-break-if->=-named/imm32/next
14412 _Primitive-break-if->=-named:  # (payload primitive)
14413     0x11/imm32/alloc-id:fake:payload
14414     0x11/imm32/alloc-id:fake
14415     _string-break-if->=/imm32/name
14416     0x11/imm32/alloc-id:fake
14417     Single-lit-var/imm32/inouts
14418     0/imm32/no-outputs
14419     0/imm32/no-outputs
14420     0x11/imm32/alloc-id:fake
14421     _string_0f_8d_jump_label/imm32/subx-name
14422     0/imm32/no-rm32
14423     0/imm32/no-r32
14424     0/imm32/no-imm32
14425     1/imm32/disp32-is-first-inout
14426     0/imm32/no-output
14427     0x11/imm32/alloc-id:fake
14428     _Primitive-break-if-<=-named/imm32/next
14429 _Primitive-break-if-<=-named:  # (payload primitive)
14430     0x11/imm32/alloc-id:fake:payload
14431     0x11/imm32/alloc-id:fake
14432     _string-break-if-<=/imm32/name
14433     0x11/imm32/alloc-id:fake
14434     Single-lit-var/imm32/inouts
14435     0/imm32/no-outputs
14436     0/imm32/no-outputs
14437     0x11/imm32/alloc-id:fake
14438     _string_0f_8e_jump_label/imm32/subx-name
14439     0/imm32/no-rm32
14440     0/imm32/no-r32
14441     0/imm32/no-imm32
14442     1/imm32/disp32-is-first-inout
14443     0/imm32/no-output
14444     0x11/imm32/alloc-id:fake
14445     _Primitive-break-if->-named/imm32/next
14446 _Primitive-break-if->-named:  # (payload primitive)
14447     0x11/imm32/alloc-id:fake:payload
14448     0x11/imm32/alloc-id:fake
14449     _string-break-if->/imm32/name
14450     0x11/imm32/alloc-id:fake
14451     Single-lit-var/imm32/inouts
14452     0/imm32/no-outputs
14453     0/imm32/no-outputs
14454     0x11/imm32/alloc-id:fake
14455     _string_0f_8f_jump_label/imm32/subx-name
14456     0/imm32/no-rm32
14457     0/imm32/no-r32
14458     0/imm32/no-imm32
14459     1/imm32/disp32-is-first-inout
14460     0/imm32/no-output
14461     0x11/imm32/alloc-id:fake
14462     _Primitive-break-named/imm32/next
14463 _Primitive-break-named:  # (payload primitive)
14464     0x11/imm32/alloc-id:fake:payload
14465     0x11/imm32/alloc-id:fake
14466     _string-break/imm32/name
14467     0x11/imm32/alloc-id:fake
14468     Single-lit-var/imm32/inouts
14469     0/imm32/no-outputs
14470     0/imm32/no-outputs
14471     0x11/imm32/alloc-id:fake
14472     _string_e9_jump_label/imm32/subx-name
14473     0/imm32/no-rm32
14474     0/imm32/no-r32
14475     0/imm32/no-imm32
14476     1/imm32/disp32-is-first-inout
14477     0/imm32/no-output
14478     0x11/imm32/alloc-id:fake
14479     _Primitive-loop-if-addr<-named/imm32/next
14480 _Primitive-loop-if-addr<-named:  # (payload primitive)
14481     0x11/imm32/alloc-id:fake:payload
14482     0x11/imm32/alloc-id:fake
14483     _string-loop-if-addr</imm32/name
14484     0x11/imm32/alloc-id:fake
14485     Single-lit-var/imm32/inouts
14486     0/imm32/no-outputs
14487     0/imm32/no-outputs
14488     0x11/imm32/alloc-id:fake
14489     _string_0f_82_jump_label/imm32/subx-name
14490     0/imm32/no-rm32
14491     0/imm32/no-r32
14492     0/imm32/no-imm32
14493     1/imm32/disp32-is-first-inout
14494     0/imm32/no-output
14495     0x11/imm32/alloc-id:fake
14496     _Primitive-loop-if-addr>=-named/imm32/next
14497 _Primitive-loop-if-addr>=-named:  # (payload primitive)
14498     0x11/imm32/alloc-id:fake:payload
14499     0x11/imm32/alloc-id:fake
14500     _string-loop-if-addr>=/imm32/name
14501     0x11/imm32/alloc-id:fake
14502     Single-lit-var/imm32/inouts
14503     0/imm32/no-outputs
14504     0/imm32/no-outputs
14505     0x11/imm32/alloc-id:fake
14506     _string_0f_83_jump_label/imm32/subx-name
14507     0/imm32/no-rm32
14508     0/imm32/no-r32
14509     0/imm32/no-imm32
14510     1/imm32/disp32-is-first-inout
14511     0/imm32/no-output
14512     0x11/imm32/alloc-id:fake
14513     _Primitive-loop-if-=-named/imm32/next
14514 _Primitive-loop-if-=-named:  # (payload primitive)
14515     0x11/imm32/alloc-id:fake:payload
14516     0x11/imm32/alloc-id:fake
14517     _string-loop-if-=/imm32/name
14518     0x11/imm32/alloc-id:fake
14519     Single-lit-var/imm32/inouts
14520     0/imm32/no-outputs
14521     0/imm32/no-outputs
14522     0x11/imm32/alloc-id:fake
14523     _string_0f_84_jump_label/imm32/subx-name
14524     0/imm32/no-rm32
14525     0/imm32/no-r32
14526     0/imm32/no-imm32
14527     1/imm32/disp32-is-first-inout
14528     0/imm32/no-output
14529     0x11/imm32/alloc-id:fake
14530     _Primitive-loop-if-!=-named/imm32/next
14531 _Primitive-loop-if-!=-named:  # (payload primitive)
14532     0x11/imm32/alloc-id:fake:payload
14533     0x11/imm32/alloc-id:fake
14534     _string-loop-if-!=/imm32/name
14535     0x11/imm32/alloc-id:fake
14536     Single-lit-var/imm32/inouts
14537     0/imm32/no-outputs
14538     0/imm32/no-outputs
14539     0x11/imm32/alloc-id:fake
14540     _string_0f_85_jump_label/imm32/subx-name
14541     0/imm32/no-rm32
14542     0/imm32/no-r32
14543     0/imm32/no-imm32
14544     1/imm32/disp32-is-first-inout
14545     0/imm32/no-output
14546     0x11/imm32/alloc-id:fake
14547     _Primitive-loop-if-addr<=-named/imm32/next
14548 _Primitive-loop-if-addr<=-named:  # (payload primitive)
14549     0x11/imm32/alloc-id:fake:payload
14550     0x11/imm32/alloc-id:fake
14551     _string-loop-if-addr<=/imm32/name
14552     0x11/imm32/alloc-id:fake
14553     Single-lit-var/imm32/inouts
14554     0/imm32/no-outputs
14555     0/imm32/no-outputs
14556     0x11/imm32/alloc-id:fake
14557     _string_0f_86_jump_label/imm32/subx-name
14558     0/imm32/no-rm32
14559     0/imm32/no-r32
14560     0/imm32/no-imm32
14561     1/imm32/disp32-is-first-inout
14562     0/imm32/no-output
14563     0x11/imm32/alloc-id:fake
14564     _Primitive-loop-if-addr>-named/imm32/next
14565 _Primitive-loop-if-addr>-named:  # (payload primitive)
14566     0x11/imm32/alloc-id:fake:payload
14567     0x11/imm32/alloc-id:fake
14568     _string-loop-if-addr>/imm32/name
14569     0x11/imm32/alloc-id:fake
14570     Single-lit-var/imm32/inouts
14571     0/imm32/no-outputs
14572     0/imm32/no-outputs
14573     0x11/imm32/alloc-id:fake
14574     _string_0f_87_jump_label/imm32/subx-name
14575     0/imm32/no-rm32
14576     0/imm32/no-r32
14577     0/imm32/no-imm32
14578     1/imm32/disp32-is-first-inout
14579     0/imm32/no-output
14580     0x11/imm32/alloc-id:fake
14581     _Primitive-loop-if-<-named/imm32/next
14582 _Primitive-loop-if-<-named:  # (payload primitive)
14583     0x11/imm32/alloc-id:fake:payload
14584     0x11/imm32/alloc-id:fake
14585     _string-loop-if-</imm32/name
14586     0x11/imm32/alloc-id:fake
14587     Single-lit-var/imm32/inouts
14588     0/imm32/no-outputs
14589     0/imm32/no-outputs
14590     0x11/imm32/alloc-id:fake
14591     _string_0f_8c_jump_label/imm32/subx-name
14592     0/imm32/no-rm32
14593     0/imm32/no-r32
14594     0/imm32/no-imm32
14595     1/imm32/disp32-is-first-inout
14596     0/imm32/no-output
14597     0x11/imm32/alloc-id:fake
14598     _Primitive-loop-if->=-named/imm32/next
14599 _Primitive-loop-if->=-named:  # (payload primitive)
14600     0x11/imm32/alloc-id:fake:payload
14601     0x11/imm32/alloc-id:fake
14602     _string-loop-if->=/imm32/name
14603     0x11/imm32/alloc-id:fake
14604     Single-lit-var/imm32/inouts
14605     0/imm32/no-outputs
14606     0/imm32/no-outputs
14607     0x11/imm32/alloc-id:fake
14608     _string_0f_8d_jump_label/imm32/subx-name
14609     0/imm32/no-rm32
14610     0/imm32/no-r32
14611     0/imm32/no-imm32
14612     1/imm32/disp32-is-first-inout
14613     0/imm32/no-output
14614     0x11/imm32/alloc-id:fake
14615     _Primitive-loop-if-<=-named/imm32/next
14616 _Primitive-loop-if-<=-named:  # (payload primitive)
14617     0x11/imm32/alloc-id:fake:payload
14618     0x11/imm32/alloc-id:fake
14619     _string-loop-if-<=/imm32/name
14620     0x11/imm32/alloc-id:fake
14621     Single-lit-var/imm32/inouts
14622     0/imm32/no-outputs
14623     0/imm32/no-outputs
14624     0x11/imm32/alloc-id:fake
14625     _string_0f_8e_jump_label/imm32/subx-name
14626     0/imm32/no-rm32
14627     0/imm32/no-r32
14628     0/imm32/no-imm32
14629     1/imm32/disp32-is-first-inout
14630     0/imm32/no-output
14631     0x11/imm32/alloc-id:fake
14632     _Primitive-loop-if->-named/imm32/next
14633 _Primitive-loop-if->-named:  # (payload primitive)
14634     0x11/imm32/alloc-id:fake:payload
14635     0x11/imm32/alloc-id:fake
14636     _string-loop-if->/imm32/name
14637     0x11/imm32/alloc-id:fake
14638     Single-lit-var/imm32/inouts
14639     0/imm32/no-outputs
14640     0/imm32/no-outputs
14641     0x11/imm32/alloc-id:fake
14642     _string_0f_8f_jump_label/imm32/subx-name
14643     0/imm32/no-rm32
14644     0/imm32/no-r32
14645     0/imm32/no-imm32
14646     1/imm32/disp32-is-first-inout
14647     0/imm32/no-output
14648     0x11/imm32/alloc-id:fake
14649     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
14650 _Primitive-loop-named:  # (payload primitive)
14651     0x11/imm32/alloc-id:fake:payload
14652     0x11/imm32/alloc-id:fake
14653     _string-loop/imm32/name
14654     0x11/imm32/alloc-id:fake
14655     Single-lit-var/imm32/inouts
14656     0/imm32/no-outputs
14657     0/imm32/no-outputs
14658     0x11/imm32/alloc-id:fake
14659     _string_e9_jump_label/imm32/subx-name
14660     0/imm32/no-rm32
14661     0/imm32/no-r32
14662     0/imm32/no-imm32
14663     1/imm32/disp32-is-first-inout
14664     0/imm32/no-output
14665     0/imm32/next
14666     0/imm32/next
14667 
14668 # string literals for Mu instructions
14669 _string-add:  # (payload array byte)
14670     0x11/imm32/alloc-id:fake:payload
14671     # "add"
14672     0x3/imm32/size
14673     0x61/a 0x64/d 0x64/d
14674 _string-address:  # (payload array byte)
14675     0x11/imm32/alloc-id:fake:payload
14676     # "address"
14677     0x7/imm32/size
14678     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
14679 _string-add-to:  # (payload array byte)
14680     0x11/imm32/alloc-id:fake:payload
14681     # "add-to"
14682     0x6/imm32/size
14683     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
14684 _string-and:  # (payload array byte)
14685     0x11/imm32/alloc-id:fake:payload
14686     # "and"
14687     0x3/imm32/size
14688     0x61/a 0x6e/n 0x64/d
14689 _string-and-with:  # (payload array byte)
14690     0x11/imm32/alloc-id:fake:payload
14691     # "and-with"
14692     0x8/imm32/size
14693     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14694 _string-break:  # (payload array byte)
14695     0x11/imm32/alloc-id:fake:payload
14696     # "break"
14697     0x5/imm32/size
14698     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
14699 _string-break-if-<:  # (payload array byte)
14700     0x11/imm32/alloc-id:fake:payload
14701     # "break-if-<"
14702     0xa/imm32/size
14703     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
14704 _string-break-if-<=:  # (payload array byte)
14705     0x11/imm32/alloc-id:fake:payload
14706     # "break-if-<="
14707     0xb/imm32/size
14708     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
14709 _string-break-if-=:  # (payload array byte)
14710     0x11/imm32/alloc-id:fake:payload
14711     # "break-if-="
14712     0xa/imm32/size
14713     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
14714 _string-break-if->:  # (payload array byte)
14715     0x11/imm32/alloc-id:fake:payload
14716     # "break-if->"
14717     0xa/imm32/size
14718     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
14719 _string-break-if->=:  # (payload array byte)
14720     0x11/imm32/alloc-id:fake:payload
14721     # "break-if->="
14722     0xb/imm32/size
14723     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
14724 _string-break-if-!=:  # (payload array byte)
14725     0x11/imm32/alloc-id:fake:payload
14726     # "break-if-!="
14727     0xb/imm32/size
14728     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
14729 _string-break-if-addr<:  # (payload array byte)
14730     0x11/imm32/alloc-id:fake:payload
14731     # "break-if-addr<"
14732     0xe/imm32/size
14733     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/<
14734 _string-break-if-addr<=:  # (payload array byte)
14735     0x11/imm32/alloc-id:fake:payload
14736     # "break-if-addr<="
14737     0xf/imm32/size
14738     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/=
14739 _string-break-if-addr>:  # (payload array byte)
14740     0x11/imm32/alloc-id:fake:payload
14741     # "break-if-addr>"
14742     0xe/imm32/size
14743     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/>
14744 _string-break-if-addr>=:  # (payload array byte)
14745     0x11/imm32/alloc-id:fake:payload
14746     # "break-if-addr>="
14747     0xf/imm32/size
14748     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/=
14749 _string-compare:  # (payload array byte)
14750     0x11/imm32/alloc-id:fake:payload
14751     # "compare"
14752     0x7/imm32/size
14753     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
14754 _string-copy:  # (payload array byte)
14755     0x11/imm32/alloc-id:fake:payload
14756     # "copy"
14757     0x4/imm32/size
14758     0x63/c 0x6f/o 0x70/p 0x79/y
14759 _string-copy-to:  # (payload array byte)
14760     0x11/imm32/alloc-id:fake:payload
14761     # "copy-to"
14762     0x7/imm32/size
14763     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
14764 _string-copy-byte:
14765     0x11/imm32/alloc-id:fake:payload
14766     # "copy-byte"
14767     0x9/imm32/size
14768     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
14769 _string-copy-byte-to:
14770     0x11/imm32/alloc-id:fake:payload
14771     # "copy-byte-to"
14772     0xc/imm32/size
14773     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
14774 _string-decrement:  # (payload array byte)
14775     0x11/imm32/alloc-id:fake:payload
14776     # "decrement"
14777     0x9/imm32/size
14778     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
14779 _string-increment:  # (payload array byte)
14780     0x11/imm32/alloc-id:fake:payload
14781     # "increment"
14782     0x9/imm32/size
14783     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
14784 _string-loop:  # (payload array byte)
14785     0x11/imm32/alloc-id:fake:payload
14786     # "loop"
14787     0x4/imm32/size
14788     0x6c/l 0x6f/o 0x6f/o 0x70/p
14789 _string-loop-if-<:  # (payload array byte)
14790     0x11/imm32/alloc-id:fake:payload
14791     # "loop-if-<"
14792     0x9/imm32/size
14793     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
14794 _string-loop-if-<=:  # (payload array byte)
14795     0x11/imm32/alloc-id:fake:payload
14796     # "loop-if-<="
14797     0xa/imm32/size
14798     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
14799 _string-loop-if-=:  # (payload array byte)
14800     0x11/imm32/alloc-id:fake:payload
14801     # "loop-if-="
14802     0x9/imm32/size
14803     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
14804 _string-loop-if->:  # (payload array byte)
14805     0x11/imm32/alloc-id:fake:payload
14806     # "loop-if->"
14807     0x9/imm32/size
14808     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
14809 _string-loop-if->=:  # (payload array byte)
14810     0x11/imm32/alloc-id:fake:payload
14811     # "loop-if->="
14812     0xa/imm32/size
14813     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
14814 _string-loop-if-!=:  # (payload array byte)
14815     0x11/imm32/alloc-id:fake:payload
14816     # "loop-if-!="
14817     0xa/imm32/size
14818     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
14819 _string-loop-if-addr<:  # (payload array byte)
14820     0x11/imm32/alloc-id:fake:payload
14821     # "loop-if-addr<"
14822     0xd/imm32/size
14823     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/<
14824 _string-loop-if-addr<=:  # (payload array byte)
14825     0x11/imm32/alloc-id:fake:payload
14826     # "loop-if-addr<="
14827     0xe/imm32/size
14828     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/=
14829 _string-loop-if-addr>:  # (payload array byte)
14830     0x11/imm32/alloc-id:fake:payload
14831     # "loop-if-addr>"
14832     0xd/imm32/size
14833     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/>
14834 _string-loop-if-addr>=:  # (payload array byte)
14835     0x11/imm32/alloc-id:fake:payload
14836     # "loop-if-addr>="
14837     0xe/imm32/size
14838     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/=
14839 _string-multiply:  # (payload array byte)
14840     0x11/imm32/alloc-id:fake:payload
14841     # "multiply"
14842     0x8/imm32/size
14843     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
14844 _string-or:  # (payload array byte)
14845     0x11/imm32/alloc-id:fake:payload
14846     # "or"
14847     0x2/imm32/size
14848     0x6f/o 0x72/r
14849 _string-or-with:  # (payload array byte)
14850     0x11/imm32/alloc-id:fake:payload
14851     # "or-with"
14852     0x7/imm32/size
14853     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14854 _string-subtract:  # (payload array byte)
14855     0x11/imm32/alloc-id:fake:payload
14856     # "subtract"
14857     0x8/imm32/size
14858     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
14859 _string-subtract-from:  # (payload array byte)
14860     0x11/imm32/alloc-id:fake:payload
14861     # "subtract-from"
14862     0xd/imm32/size
14863     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
14864 _string-xor:  # (payload array byte)
14865     0x11/imm32/alloc-id:fake:payload
14866     # "xor"
14867     0x3/imm32/size
14868     0x78/x 0x6f/o 0x72/r
14869 _string-xor-with:  # (payload array byte)
14870     0x11/imm32/alloc-id:fake:payload
14871     # "xor-with"
14872     0x8/imm32/size
14873     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14874 
14875 # string literals for SubX instructions
14876 _string_01_add_to:  # (payload array byte)
14877     0x11/imm32/alloc-id:fake:payload
14878     # "01/add-to"
14879     0x9/imm32/size
14880     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
14881 _string_03_add:  # (payload array byte)
14882     0x11/imm32/alloc-id:fake:payload
14883     # "03/add"
14884     0x6/imm32/size
14885     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
14886 _string_05_add_to_eax:  # (payload array byte)
14887     0x11/imm32/alloc-id:fake:payload
14888     # "05/add-to-eax"
14889     0xd/imm32/size
14890     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
14891 _string_09_or_with:  # (payload array byte)
14892     0x11/imm32/alloc-id:fake:payload
14893     # "09/or-with"
14894     0xa/imm32/size
14895     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14896 _string_0b_or:  # (payload array byte)
14897     0x11/imm32/alloc-id:fake:payload
14898     # "0b/or"
14899     0x5/imm32/size
14900     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
14901 _string_0d_or_with_eax:  # (payload array byte)
14902     0x11/imm32/alloc-id:fake:payload
14903     # "0d/or-with-eax"
14904     0xe/imm32/size
14905     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
14906 _string_0f_82_jump_label:  # (payload array byte)
14907     0x11/imm32/alloc-id:fake:payload
14908     # "0f 82/jump-if-addr<"
14909     0x13/imm32/size
14910     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/<
14911 _string_0f_82_jump_break:  # (payload array byte)
14912     0x11/imm32/alloc-id:fake:payload
14913     # "0f 82/jump-if-addr< break/disp32"
14914     0x20/imm32/size
14915     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
14916 _string_0f_82_jump_loop:  # (payload array byte)
14917     0x11/imm32/alloc-id:fake:payload
14918     # "0f 82/jump-if-addr< loop/disp32"
14919     0x1f/imm32/size
14920     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
14921 _string_0f_83_jump_label:  # (payload array byte)
14922     0x11/imm32/alloc-id:fake:payload
14923     # "0f 83/jump-if-addr>="
14924     0x14/imm32/size
14925     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/=
14926 _string_0f_83_jump_break:  # (payload array byte)
14927     0x11/imm32/alloc-id:fake:payload
14928     # "0f 83/jump-if-addr>= break/disp32"
14929     0x21/imm32/size
14930     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
14931 _string_0f_83_jump_loop:  # (payload array byte)
14932     0x11/imm32/alloc-id:fake:payload
14933     # "0f 83/jump-if-addr>= loop/disp32"
14934     0x20/imm32/size
14935     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
14936 _string_0f_84_jump_label:  # (payload array byte)
14937     0x11/imm32/alloc-id:fake:payload
14938     # "0f 84/jump-if-="
14939     0xf/imm32/size
14940     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/=
14941 _string_0f_84_jump_break:  # (payload array byte)
14942     0x11/imm32/alloc-id:fake:payload
14943     # "0f 84/jump-if-= break/disp32"
14944     0x1c/imm32/size
14945     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
14946 _string_0f_84_jump_loop:  # (payload array byte)
14947     0x11/imm32/alloc-id:fake:payload
14948     # "0f 84/jump-if-= loop/disp32"
14949     0x1b/imm32/size
14950     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
14951 _string_0f_85_jump_label:  # (payload array byte)
14952     0x11/imm32/alloc-id:fake:payload
14953     # "0f 85/jump-if-!="
14954     0x10/imm32/size
14955     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/=
14956 _string_0f_85_jump_break:  # (payload array byte)
14957     0x11/imm32/alloc-id:fake:payload
14958     # "0f 85/jump-if-!= break/disp32"
14959     0x1d/imm32/size
14960     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
14961 _string_0f_85_jump_loop:  # (payload array byte)
14962     0x11/imm32/alloc-id:fake:payload
14963     # "0f 85/jump-if-!= loop/disp32"
14964     0x1c/imm32/size
14965     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
14966 _string_0f_86_jump_label:  # (payload array byte)
14967     0x11/imm32/alloc-id:fake:payload
14968     # "0f 86/jump-if-addr<="
14969     0x14/imm32/size
14970     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/=
14971 _string_0f_86_jump_break:  # (payload array byte)
14972     0x11/imm32/alloc-id:fake:payload
14973     # "0f 86/jump-if-addr<= break/disp32"
14974     0x21/imm32/size
14975     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
14976 _string_0f_86_jump_loop:  # (payload array byte)
14977     0x11/imm32/alloc-id:fake:payload
14978     # "0f 86/jump-if-addr<= loop/disp32"
14979     0x20/imm32/size
14980     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
14981 _string_0f_87_jump_label:  # (payload array byte)
14982     0x11/imm32/alloc-id:fake:payload
14983     # "0f 87/jump-if-addr>"
14984     0x13/imm32/size
14985     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/>
14986 _string_0f_87_jump_break:  # (payload array byte)
14987     0x11/imm32/alloc-id:fake:payload
14988     # "0f 87/jump-if-addr> break/disp32"
14989     0x20/imm32/size
14990     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
14991 _string_0f_87_jump_loop:  # (payload array byte)
14992     0x11/imm32/alloc-id:fake:payload
14993     # "0f 87/jump-if-addr> loop/disp32"
14994     0x1f/imm32/size
14995     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
14996 _string_0f_8c_jump_label:  # (payload array byte)
14997     0x11/imm32/alloc-id:fake:payload
14998     # "0f 8c/jump-if-<"
14999     0xf/imm32/size
15000     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/<
15001 _string_0f_8c_jump_break:  # (payload array byte)
15002     0x11/imm32/alloc-id:fake:payload
15003     # "0f 8c/jump-if-< break/disp32"
15004     0x1c/imm32/size
15005     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
15006 _string_0f_8c_jump_loop:  # (payload array byte)
15007     0x11/imm32/alloc-id:fake:payload
15008     # "0f 8c/jump-if-< loop/disp32"
15009     0x1b/imm32/size
15010     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
15011 _string_0f_8d_jump_label:  # (payload array byte)
15012     0x11/imm32/alloc-id:fake:payload
15013     # "0f 8d/jump-if->="
15014     0x10/imm32/size
15015     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/=
15016 _string_0f_8d_jump_break:  # (payload array byte)
15017     0x11/imm32/alloc-id:fake:payload
15018     # "0f 8d/jump-if->= break/disp32"
15019     0x1d/imm32/size
15020     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
15021 _string_0f_8d_jump_loop:  # (payload array byte)
15022     0x11/imm32/alloc-id:fake:payload
15023     # "0f 8d/jump-if->= loop/disp32"
15024     0x1c/imm32/size
15025     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
15026 _string_0f_8e_jump_label:  # (payload array byte)
15027     0x11/imm32/alloc-id:fake:payload
15028     # "0f 8e/jump-if-<="
15029     0x10/imm32/size
15030     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/=
15031 _string_0f_8e_jump_break:  # (payload array byte)
15032     0x11/imm32/alloc-id:fake:payload
15033     # "0f 8e/jump-if-<= break/disp32"
15034     0x1d/imm32/size
15035     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
15036 _string_0f_8e_jump_loop:  # (payload array byte)
15037     0x11/imm32/alloc-id:fake:payload
15038     # "0f 8e/jump-if-<= loop/disp32"
15039     0x1c/imm32/size
15040     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
15041 _string_0f_8f_jump_label:  # (payload array byte)
15042     0x11/imm32/alloc-id:fake:payload
15043     # "0f 8f/jump-if->"
15044     0xf/imm32/size
15045     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/>
15046 _string_0f_8f_jump_break:  # (payload array byte)
15047     0x11/imm32/alloc-id:fake:payload
15048     # "0f 8f/jump-if-> break/disp32"
15049     0x1c/imm32/size
15050     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
15051 _string_0f_8f_jump_loop:  # (payload array byte)
15052     0x11/imm32/alloc-id:fake:payload
15053     # "0f 8f/jump-if-> loop/disp32"
15054     0x1b/imm32/size
15055     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
15056 _string_0f_af_multiply:  # (payload array byte)
15057     0x11/imm32/alloc-id:fake:payload
15058     # "0f af/multiply"
15059     0xe/imm32/size
15060     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
15061 _string_21_and_with:  # (payload array byte)
15062     0x11/imm32/alloc-id:fake:payload
15063     # "21/and-with"
15064     0xb/imm32/size
15065     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
15066 _string_23_and:  # (payload array byte)
15067     0x11/imm32/alloc-id:fake:payload
15068     # "23/and"
15069     0x6/imm32/size
15070     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
15071 _string_25_and_with_eax:  # (payload array byte)
15072     0x11/imm32/alloc-id:fake:payload
15073     # "25/and-with-eax"
15074     0xf/imm32/size
15075     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
15076 _string_29_subtract_from:  # (payload array byte)
15077     0x11/imm32/alloc-id:fake:payload
15078     # "29/subtract-from"
15079     0x10/imm32/size
15080     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
15081 _string_2b_subtract:  # (payload array byte)
15082     0x11/imm32/alloc-id:fake:payload
15083     # "2b/subtract"
15084     0xb/imm32/size
15085     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
15086 _string_2d_subtract_from_eax:  # (payload array byte)
15087     0x11/imm32/alloc-id:fake:payload
15088     # "2d/subtract-from-eax"
15089     0x14/imm32/size
15090     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
15091 _string_31_xor_with:  # (payload array byte)
15092     0x11/imm32/alloc-id:fake:payload
15093     # "31/xor-with"
15094     0xb/imm32/size
15095     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
15096 _string_33_xor:  # (payload array byte)
15097     0x11/imm32/alloc-id:fake:payload
15098     # "33/xor"
15099     0x6/imm32/size
15100     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
15101 _string_35_xor_with_eax:  # (payload array byte)
15102     0x11/imm32/alloc-id:fake:payload
15103     # "35/xor-with-eax"
15104     0xf/imm32/size
15105     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
15106 _string_39_compare->:  # (payload array byte)
15107     0x11/imm32/alloc-id:fake:payload
15108     # "39/compare->"
15109     0xc/imm32/size
15110     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
15111 _string_3b_compare<-:  # (payload array byte)
15112     0x11/imm32/alloc-id:fake:payload
15113     # "3b/compare<-"
15114     0xc/imm32/size
15115     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
15116 _string_3d_compare_eax_with:  # (payload array byte)
15117     0x11/imm32/alloc-id:fake:payload
15118     # "3d/compare-eax-with"
15119     0x13/imm32/size
15120     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
15121 _string_40_increment_eax:  # (payload array byte)
15122     0x11/imm32/alloc-id:fake:payload
15123     # "40/increment-eax"
15124     0x10/imm32/size
15125     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
15126 _string_41_increment_ecx:  # (payload array byte)
15127     0x11/imm32/alloc-id:fake:payload
15128     # "41/increment-ecx"
15129     0x10/imm32/size
15130     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
15131 _string_42_increment_edx:  # (payload array byte)
15132     0x11/imm32/alloc-id:fake:payload
15133     # "42/increment-edx"
15134     0x10/imm32/size
15135     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
15136 _string_43_increment_ebx:  # (payload array byte)
15137     0x11/imm32/alloc-id:fake:payload
15138     # "43/increment-ebx"
15139     0x10/imm32/size
15140     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
15141 _string_46_increment_esi:  # (payload array byte)
15142     0x11/imm32/alloc-id:fake:payload
15143     # "46/increment-esi"
15144     0x10/imm32/size
15145     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
15146 _string_47_increment_edi:  # (payload array byte)
15147     0x11/imm32/alloc-id:fake:payload
15148     # "47/increment-edi"
15149     0x10/imm32/size
15150     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
15151 _string_48_decrement_eax:  # (payload array byte)
15152     0x11/imm32/alloc-id:fake:payload
15153     # "48/decrement-eax"
15154     0x10/imm32/size
15155     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
15156 _string_49_decrement_ecx:  # (payload array byte)
15157     0x11/imm32/alloc-id:fake:payload
15158     # "49/decrement-ecx"
15159     0x10/imm32/size
15160     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
15161 _string_4a_decrement_edx:  # (payload array byte)
15162     0x11/imm32/alloc-id:fake:payload
15163     # "4a/decrement-edx"
15164     0x10/imm32/size
15165     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
15166 _string_4b_decrement_ebx:  # (payload array byte)
15167     0x11/imm32/alloc-id:fake:payload
15168     # "4b/decrement-ebx"
15169     0x10/imm32/size
15170     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
15171 _string_4e_decrement_esi:  # (payload array byte)
15172     0x11/imm32/alloc-id:fake:payload
15173     # "4e/decrement-esi"
15174     0x10/imm32/size
15175     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
15176 _string_4f_decrement_edi:  # (payload array byte)
15177     0x11/imm32/alloc-id:fake:payload
15178     # "4f/decrement-edi"
15179     0x10/imm32/size
15180     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
15181 _string_81_subop_add:  # (payload array byte)
15182     0x11/imm32/alloc-id:fake:payload
15183     # "81 0/subop/add"
15184     0xe/imm32/size
15185     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
15186 _string_81_subop_or:  # (payload array byte)
15187     0x11/imm32/alloc-id:fake:payload
15188     # "81 1/subop/or"
15189     0xd/imm32/size
15190     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
15191 _string_81_subop_and:  # (payload array byte)
15192     0x11/imm32/alloc-id:fake:payload
15193     # "81 4/subop/and"
15194     0xe/imm32/size
15195     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
15196 _string_81_subop_subtract:  # (payload array byte)
15197     0x11/imm32/alloc-id:fake:payload
15198     # "81 5/subop/subtract"
15199     0x13/imm32/size
15200     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
15201 _string_81_subop_xor:  # (payload array byte)
15202     0x11/imm32/alloc-id:fake:payload
15203     # "81 6/subop/xor"
15204     0xe/imm32/size
15205     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
15206 _string_81_subop_compare:  # (payload array byte)
15207     0x11/imm32/alloc-id:fake:payload
15208     # "81 7/subop/compare"
15209     0x12/imm32/size
15210     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
15211 _string_89_<-:  # (payload array byte)
15212     0x11/imm32/alloc-id:fake:payload
15213     # "89/<-"
15214     0x5/imm32/size
15215     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
15216 _string_8b_->:  # (payload array byte)
15217     0x11/imm32/alloc-id:fake:payload
15218     # "8b/->"
15219     0x5/imm32/size
15220     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
15221 _string_8a_copy_byte:
15222     0x11/imm32/alloc-id:fake:payload
15223     # "8a/byte->"
15224     0x9/imm32/size
15225     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
15226 _string_88_copy_byte:
15227     0x11/imm32/alloc-id:fake:payload
15228     # "88/byte<-"
15229     0x9/imm32/size
15230     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
15231 _string_8d_copy_address:  # (payload array byte)
15232     0x11/imm32/alloc-id:fake:payload
15233     # "8d/copy-address"
15234     0xf/imm32/size
15235     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
15236 _string_b8_copy_to_eax:  # (payload array byte)
15237     0x11/imm32/alloc-id:fake:payload
15238     # "b8/copy-to-eax"
15239     0xe/imm32/size
15240     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
15241 _string_b9_copy_to_ecx:  # (payload array byte)
15242     0x11/imm32/alloc-id:fake:payload
15243     # "b9/copy-to-ecx"
15244     0xe/imm32/size
15245     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
15246 _string_ba_copy_to_edx:  # (payload array byte)
15247     0x11/imm32/alloc-id:fake:payload
15248     # "ba/copy-to-edx"
15249     0xe/imm32/size
15250     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
15251 _string_bb_copy_to_ebx:  # (payload array byte)
15252     0x11/imm32/alloc-id:fake:payload
15253     # "bb/copy-to-ebx"
15254     0xe/imm32/size
15255     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
15256 _string_be_copy_to_esi:  # (payload array byte)
15257     0x11/imm32/alloc-id:fake:payload
15258     # "be/copy-to-esi"
15259     0xe/imm32/size
15260     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
15261 _string_bf_copy_to_edi:  # (payload array byte)
15262     0x11/imm32/alloc-id:fake:payload
15263     # "bf/copy-to-edi"
15264     0xe/imm32/size
15265     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
15266 _string_c7_subop_copy:  # (payload array byte)
15267     0x11/imm32/alloc-id:fake:payload
15268     # "c7 0/subop/copy"
15269     0xf/imm32/size
15270     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
15271 _string_e9_jump_label:  # (payload array byte)
15272     0x11/imm32/alloc-id:fake:payload
15273     # "e9/jump"
15274     0x7/imm32/size
15275     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
15276 _string_e9_jump_break:  # (payload array byte)
15277     0x11/imm32/alloc-id:fake:payload
15278     # "e9/jump break/disp32"
15279     0x14/imm32/size
15280     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
15281 _string_e9_jump_loop:  # (payload array byte)
15282     0x11/imm32/alloc-id:fake:payload
15283     # "e9/jump loop/disp32"
15284     0x13/imm32/size
15285     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
15286 _string_ff_subop_increment:  # (payload array byte)
15287     0x11/imm32/alloc-id:fake:payload
15288     # "ff 0/subop/increment"
15289     0x14/imm32/size
15290     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
15291 _string_ff_subop_decrement:  # (payload array byte)
15292     0x11/imm32/alloc-id:fake:payload
15293     # "ff 1/subop/decrement"
15294     0x14/imm32/size
15295     0x66/f 0x66/f 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
15296 
15297 Single-int-var-in-mem:  # (payload list var)
15298     0x11/imm32/alloc-id:fake:payload
15299     0x11/imm32/alloc-id:fake
15300     Int-var-in-mem/imm32
15301     0/imm32/next
15302     0/imm32/next
15303 
15304 Int-var-in-mem:  # (payload var)
15305     0x11/imm32/alloc-id:fake:payload
15306     0/imm32/name
15307     0/imm32/name
15308     0x11/imm32/alloc-id:fake
15309     Type-int/imm32
15310     1/imm32/some-block-depth
15311     1/imm32/some-stack-offset
15312     0/imm32/no-register
15313     0/imm32/no-register
15314 
15315 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
15316 Single-byte-var-in-mem:  # (payload list var)
15317     0x11/imm32/alloc-id:fake:payload
15318     0x11/imm32/alloc-id:fake
15319     Byte-var-in-mem/imm32
15320     0/imm32/next
15321     0/imm32/next
15322 
15323 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
15324 Byte-var-in-mem:  # (payload var)
15325     0x11/imm32/alloc-id:fake:payload
15326     0/imm32/name
15327     0/imm32/name
15328     0x11/imm32/alloc-id:fake
15329     Type-byte/imm32
15330     1/imm32/some-block-depth
15331     1/imm32/some-stack-offset
15332     0/imm32/no-register
15333     0/imm32/no-register
15334 
15335 Two-args-int-stack-int-reg:  # (payload list var)
15336     0x11/imm32/alloc-id:fake:payload
15337     0x11/imm32/alloc-id:fake
15338     Int-var-in-mem/imm32
15339     0x11/imm32/alloc-id:fake
15340     Single-int-var-in-some-register/imm32/next
15341 
15342 Two-int-args-in-regs:  # (payload list var)
15343     0x11/imm32/alloc-id:fake:payload
15344     0x11/imm32/alloc-id:fake
15345     Int-var-in-some-register/imm32
15346     0x11/imm32/alloc-id:fake
15347     Single-int-var-in-some-register/imm32/next
15348 
15349 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
15350 Two-args-byte-stack-byte-reg:  # (payload list var)
15351     0x11/imm32/alloc-id:fake:payload
15352     0x11/imm32/alloc-id:fake
15353     Byte-var-in-mem/imm32
15354     0x11/imm32/alloc-id:fake
15355     Single-byte-var-in-some-register/imm32/next
15356 
15357 Two-args-int-reg-int-stack:  # (payload list var)
15358     0x11/imm32/alloc-id:fake:payload
15359     0x11/imm32/alloc-id:fake
15360     Int-var-in-some-register/imm32
15361     0x11/imm32/alloc-id:fake
15362     Single-int-var-in-mem/imm32/next
15363 
15364 Two-args-int-eax-int-literal:  # (payload list var)
15365     0x11/imm32/alloc-id:fake:payload
15366     0x11/imm32/alloc-id:fake
15367     Int-var-in-eax/imm32
15368     0x11/imm32/alloc-id:fake
15369     Single-lit-var/imm32/next
15370 
15371 Int-var-and-literal:  # (payload list var)
15372     0x11/imm32/alloc-id:fake:payload
15373     0x11/imm32/alloc-id:fake
15374     Int-var-in-mem/imm32
15375     0x11/imm32/alloc-id:fake
15376     Single-lit-var/imm32/next
15377 
15378 Int-var-in-register-and-literal:  # (payload list var)
15379     0x11/imm32/alloc-id:fake:payload
15380     0x11/imm32/alloc-id:fake
15381     Int-var-in-some-register/imm32
15382     0x11/imm32/alloc-id:fake
15383     Single-lit-var/imm32/next
15384 
15385 Single-int-var-in-some-register:  # (payload list var)
15386     0x11/imm32/alloc-id:fake:payload
15387     0x11/imm32/alloc-id:fake
15388     Int-var-in-some-register/imm32
15389     0/imm32/next
15390     0/imm32/next
15391 
15392 Single-addr-var-in-some-register:  # (payload list var)
15393     0x11/imm32/alloc-id:fake:payload
15394     0x11/imm32/alloc-id:fake
15395     Addr-var-in-some-register/imm32
15396     0/imm32/next
15397     0/imm32/next
15398 
15399 Single-byte-var-in-some-register:  # (payload list var)
15400     0x11/imm32/alloc-id:fake:payload
15401     0x11/imm32/alloc-id:fake
15402     Byte-var-in-some-register/imm32
15403     0/imm32/next
15404     0/imm32/next
15405 
15406 Int-var-in-some-register:  # (payload var)
15407     0x11/imm32/alloc-id:fake:payload
15408     0/imm32/name
15409     0/imm32/name
15410     0x11/imm32/alloc-id:fake
15411     Type-int/imm32
15412     1/imm32/some-block-depth
15413     0/imm32/no-stack-offset
15414     0x11/imm32/alloc-id:fake
15415     Any-register/imm32
15416 
15417 Any-register:  # (payload array byte)
15418     0x11/imm32/alloc-id:fake:payload
15419     1/imm32/size
15420     # data
15421     2a/asterisk
15422 
15423 Addr-var-in-some-register:  # (payload var)
15424     0x11/imm32/alloc-id:fake:payload
15425     0/imm32/name
15426     0/imm32/name
15427     0x11/imm32/alloc-id:fake
15428     Type-addr/imm32
15429     1/imm32/some-block-depth
15430     0/imm32/no-stack-offset
15431     0x11/imm32/alloc-id:fake
15432     Any-register/imm32
15433 
15434 Byte-var-in-some-register:  # (payload var)
15435     0x11/imm32/alloc-id:fake:payload
15436     0/imm32/name
15437     0/imm32/name
15438     0x11/imm32/alloc-id:fake
15439     Type-byte/imm32
15440     1/imm32/some-block-depth
15441     0/imm32/no-stack-offset
15442     0x11/imm32/alloc-id:fake
15443     Any-register/imm32
15444 
15445 Single-int-var-in-eax:  # (payload list var)
15446     0x11/imm32/alloc-id:fake:payload
15447     0x11/imm32/alloc-id:fake
15448     Int-var-in-eax/imm32
15449     0/imm32/next
15450     0/imm32/next
15451 
15452 Int-var-in-eax:
15453     0x11/imm32/alloc-id:fake:payload
15454     0/imm32/name
15455     0/imm32/name
15456     0x11/imm32/alloc-id:fake
15457     Type-int/imm32
15458     1/imm32/some-block-depth
15459     0/imm32/no-stack-offset
15460     0x11/imm32/alloc-id:fake
15461     $Register-eax/imm32
15462 
15463 Single-int-var-in-ecx:  # (payload list var)
15464     0x11/imm32/alloc-id:fake:payload
15465     0x11/imm32/alloc-id:fake
15466     Int-var-in-ecx/imm32
15467     0/imm32/next
15468     0/imm32/next
15469 
15470 Int-var-in-ecx:
15471     0x11/imm32/alloc-id:fake:payload
15472     0/imm32/name
15473     0/imm32/name
15474     0x11/imm32/alloc-id:fake
15475     Type-int/imm32
15476     1/imm32/some-block-depth
15477     0/imm32/no-stack-offset
15478     0x11/imm32/alloc-id:fake
15479     $Register-ecx/imm32/register
15480 
15481 Single-int-var-in-edx:  # (payload list var)
15482     0x11/imm32/alloc-id:fake:payload
15483     0x11/imm32/alloc-id:fake
15484     Int-var-in-edx/imm32
15485     0/imm32/next
15486     0/imm32/next
15487 
15488 Int-var-in-edx:  # (payload list var)
15489     0x11/imm32/alloc-id:fake:payload
15490     0/imm32/name
15491     0/imm32/name
15492     0x11/imm32/alloc-id:fake
15493     Type-int/imm32
15494     1/imm32/some-block-depth
15495     0/imm32/no-stack-offset
15496     0x11/imm32/alloc-id:fake
15497     $Register-edx/imm32/register
15498 
15499 Single-int-var-in-ebx:  # (payload list var)
15500     0x11/imm32/alloc-id:fake:payload
15501     0x11/imm32/alloc-id:fake
15502     Int-var-in-ebx/imm32
15503     0/imm32/next
15504     0/imm32/next
15505 
15506 Int-var-in-ebx:  # (payload list var)
15507     0x11/imm32/alloc-id:fake:payload
15508     0/imm32/name
15509     0/imm32/name
15510     0x11/imm32/alloc-id:fake
15511     Type-int/imm32
15512     1/imm32/some-block-depth
15513     0/imm32/no-stack-offset
15514     0x11/imm32/alloc-id:fake
15515     $Register-ebx/imm32/register
15516 
15517 Single-int-var-in-esi:  # (payload list var)
15518     0x11/imm32/alloc-id:fake:payload
15519     0x11/imm32/alloc-id:fake
15520     Int-var-in-esi/imm32
15521     0/imm32/next
15522     0/imm32/next
15523 
15524 Int-var-in-esi:  # (payload list var)
15525     0x11/imm32/alloc-id:fake:payload
15526     0/imm32/name
15527     0/imm32/name
15528     0x11/imm32/alloc-id:fake
15529     Type-int/imm32
15530     1/imm32/some-block-depth
15531     0/imm32/no-stack-offset
15532     0x11/imm32/alloc-id:fake
15533     $Register-esi/imm32/register
15534 
15535 Single-int-var-in-edi:  # (payload list var)
15536     0x11/imm32/alloc-id:fake:payload
15537     0x11/imm32/alloc-id:fake
15538     Int-var-in-edi/imm32
15539     0/imm32/next
15540     0/imm32/next
15541 
15542 Int-var-in-edi:  # (payload list var)
15543     0x11/imm32/alloc-id:fake:payload
15544     0/imm32/name
15545     0/imm32/name
15546     0x11/imm32/alloc-id:fake
15547     Type-int/imm32
15548     1/imm32/some-block-depth
15549     0/imm32/no-stack-offset
15550     0x11/imm32/alloc-id:fake
15551     $Register-edi/imm32/register
15552 
15553 Single-lit-var:  # (payload list var)
15554     0x11/imm32/alloc-id:fake:payload
15555     0x11/imm32/alloc-id:fake
15556     Lit-var/imm32
15557     0/imm32/next
15558     0/imm32/next
15559 
15560 Lit-var:  # (payload var)
15561     0x11/imm32/alloc-id:fake:payload
15562     0/imm32/name
15563     0/imm32/name
15564     0x11/imm32/alloc-id:fake
15565     Type-literal/imm32
15566     1/imm32/some-block-depth
15567     0/imm32/no-stack-offset
15568     0/imm32/no-register
15569     0/imm32/no-register
15570 
15571 Type-int:  # (payload tree type-id)
15572     0x11/imm32/alloc-id:fake:payload
15573     1/imm32/left-is-atom
15574     1/imm32/value:int
15575     0/imm32/left:unused
15576     0/imm32/right:null
15577     0/imm32/right:null
15578 
15579 Type-literal:  # (payload tree type-id)
15580     0x11/imm32/alloc-id:fake:payload
15581     1/imm32/is-atom
15582     0/imm32/value:literal
15583     0/imm32/left:unused
15584     0/imm32/right:null
15585     0/imm32/right:null
15586 
15587 Type-addr:  # (payload tree type-id)
15588     0x11/imm32/alloc-id:fake:payload
15589     1/imm32/is-atom
15590     2/imm32/value:addr
15591     0/imm32/left:unused
15592     0/imm32/right:null
15593     0/imm32/right:null
15594 
15595 Type-byte:  # (payload tree type-id)
15596     0x11/imm32/alloc-id:fake:payload
15597     1/imm32/is-atom
15598     8/imm32/value:byte
15599     0/imm32/left:unused
15600     0/imm32/right:null
15601     0/imm32/right:null
15602 
15603 == code
15604 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
15605     # . prologue
15606     55/push-ebp
15607     89/<- %ebp 4/r32/esp
15608     # . save registers
15609     50/push-eax
15610     51/push-ecx
15611     # ecx = primitive
15612     8b/-> *(ebp+0x10) 1/r32/ecx
15613     # emit primitive name
15614     (emit-indent *(ebp+8) *Curr-block-depth)
15615     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
15616     (write-buffered *(ebp+8) %eax)
15617     # emit rm32 if necessary
15618     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
15619     # emit r32 if necessary
15620     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
15621     # emit imm32 if necessary
15622     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
15623     # emit disp32 if necessary
15624     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
15625     (write-buffered *(ebp+8) Newline)
15626 $emit-subx-primitive:end:
15627     # . restore registers
15628     59/pop-to-ecx
15629     58/pop-to-eax
15630     # . epilogue
15631     89/<- %esp 5/r32/ebp
15632     5d/pop-to-ebp
15633     c3/return
15634 
15635 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15636     # . prologue
15637     55/push-ebp
15638     89/<- %ebp 4/r32/esp
15639     # . save registers
15640     50/push-eax
15641     # if (l == 0) return
15642     81 7/subop/compare *(ebp+0xc) 0/imm32
15643     74/jump-if-= $emit-subx-rm32:end/disp8
15644     # var v/eax: (addr stmt-var)
15645     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
15646     (emit-subx-var-as-rm32 *(ebp+8) %eax)
15647 $emit-subx-rm32:end:
15648     # . restore registers
15649     58/pop-to-eax
15650     # . epilogue
15651     89/<- %esp 5/r32/ebp
15652     5d/pop-to-ebp
15653     c3/return
15654 
15655 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)
15656     # . prologue
15657     55/push-ebp
15658     89/<- %ebp 4/r32/esp
15659     # . save registers
15660     51/push-ecx
15661     # eax = l
15662     8b/-> *(ebp+0xc) 0/r32/eax
15663     # ecx = stmt
15664     8b/-> *(ebp+8) 1/r32/ecx
15665     # if (l == 1) return stmt->inouts
15666     {
15667       3d/compare-eax-and 1/imm32
15668       75/jump-if-!= break/disp8
15669 $get-stmt-operand-from-arg-location:1:
15670       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15671       eb/jump $get-stmt-operand-from-arg-location:end/disp8
15672     }
15673     # if (l == 2) return stmt->inouts->next
15674     {
15675       3d/compare-eax-and 2/imm32
15676       75/jump-if-!= break/disp8
15677 $get-stmt-operand-from-arg-location:2:
15678       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15679       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15680       eb/jump $get-stmt-operand-from-arg-location:end/disp8
15681     }
15682     # if (l == 3) return stmt->outputs
15683     {
15684       3d/compare-eax-and 3/imm32
15685       75/jump-if-!= break/disp8
15686 $get-stmt-operand-from-arg-location:3:
15687       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15688       eb/jump $get-stmt-operand-from-arg-location:end/disp8
15689     }
15690     # abort
15691     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
15692 $get-stmt-operand-from-arg-location:end:
15693     # . restore registers
15694     59/pop-to-ecx
15695     # . epilogue
15696     89/<- %esp 5/r32/ebp
15697     5d/pop-to-ebp
15698     c3/return
15699 
15700 $get-stmt-operand-from-arg-location:abort:
15701     # error("invalid arg-location " eax)
15702     (write-buffered *(ebp+0x10) "invalid arg-location ")
15703     (print-int32-buffered *(ebp+0x10) %eax)
15704     (write-buffered *(ebp+0x10) Newline)
15705     (flush *(ebp+0x10))
15706     (stop *(ebp+0x14) 1)
15707     # never gets here
15708 
15709 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
15710     # . prologue
15711     55/push-ebp
15712     89/<- %ebp 4/r32/esp
15713     # . save registers
15714     50/push-eax
15715     51/push-ecx
15716     # if (l == 0) return
15717     81 7/subop/compare *(ebp+0xc) 0/imm32
15718     0f 84/jump-if-= $emit-subx-r32:end/disp32
15719     # var v/eax: (addr stmt-var)
15720     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
15721     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15722     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
15723     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
15724     (write-buffered *(ebp+8) Space)
15725     (print-int32-buffered *(ebp+8) *eax)
15726     (write-buffered *(ebp+8) "/r32")
15727 $emit-subx-r32:end:
15728     # . restore registers
15729     59/pop-to-ecx
15730     58/pop-to-eax
15731     # . epilogue
15732     89/<- %esp 5/r32/ebp
15733     5d/pop-to-ebp
15734     c3/return
15735 
15736 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
15737     # . prologue
15738     55/push-ebp
15739     89/<- %ebp 4/r32/esp
15740     # . save registers
15741     50/push-eax
15742     51/push-ecx
15743     # if (l == 0) return
15744     81 7/subop/compare *(ebp+0xc) 0/imm32
15745     0f 84/jump-if-= $emit-subx-imm32:end/disp32
15746     # var v/eax: (handle var)
15747     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
15748     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15749     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15750     (write-buffered *(ebp+8) Space)
15751     (write-buffered *(ebp+8) %eax)
15752     (write-buffered *(ebp+8) "/imm32")
15753 $emit-subx-imm32:end:
15754     # . restore registers
15755     59/pop-to-ecx
15756     58/pop-to-eax
15757     # . epilogue
15758     89/<- %esp 5/r32/ebp
15759     5d/pop-to-ebp
15760     c3/return
15761 
15762 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15763     # . prologue
15764     55/push-ebp
15765     89/<- %ebp 4/r32/esp
15766     # . save registers
15767     50/push-eax
15768     51/push-ecx
15769     # if (location == 0) return
15770     81 7/subop/compare *(ebp+0xc) 0/imm32
15771     0f 84/jump-if-= $emit-subx-disp32:end/disp32
15772     # var v/eax: (addr stmt-var)
15773     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
15774     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15775     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15776     (write-buffered *(ebp+8) Space)
15777     (write-buffered *(ebp+8) %eax)
15778     # hack: if instruction operation starts with "break", emit ":break"
15779     # var name/ecx: (addr array byte) = lookup(stmt->operation)
15780     8b/-> *(ebp+0x10) 0/r32/eax
15781     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15782     89/<- %ecx 0/r32/eax
15783     {
15784       (string-starts-with? %ecx "break")  # => eax
15785       3d/compare-eax-and 0/imm32/false
15786       74/jump-if-= break/disp8
15787       (write-buffered *(ebp+8) ":break")
15788     }
15789     # hack: if instruction operation starts with "loop", emit ":loop"
15790     {
15791       (string-starts-with? %ecx "loop")  # => eax
15792       3d/compare-eax-and 0/imm32/false
15793       74/jump-if-= break/disp8
15794       (write-buffered *(ebp+8) ":loop")
15795     }
15796     (write-buffered *(ebp+8) "/disp32")
15797 $emit-subx-disp32:end:
15798     # . restore registers
15799     59/pop-to-ecx
15800     58/pop-to-eax
15801     # . epilogue
15802     89/<- %esp 5/r32/ebp
15803     5d/pop-to-ebp
15804     c3/return
15805 
15806 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
15807     # . prologue
15808     55/push-ebp
15809     89/<- %ebp 4/r32/esp
15810     # . save registers
15811     50/push-eax
15812     51/push-ecx
15813     #
15814     (emit-indent *(ebp+8) *Curr-block-depth)
15815     (write-buffered *(ebp+8) "(")
15816     # ecx = stmt
15817     8b/-> *(ebp+0xc) 1/r32/ecx
15818     # - emit function name
15819     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15820     (write-buffered *(ebp+8) %eax)
15821     # - emit arguments
15822     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
15823     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15824     {
15825       # if (curr == null) break
15826       3d/compare-eax-and 0/imm32
15827       74/jump-if-= break/disp8
15828       #
15829       (emit-subx-call-operand *(ebp+8) %eax)
15830       # curr = lookup(curr->next)
15831       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15832       eb/jump loop/disp8
15833     }
15834     #
15835     (write-buffered *(ebp+8) ")\n")
15836 $emit-call:end:
15837     # . restore registers
15838     59/pop-to-ecx
15839     58/pop-to-eax
15840     # . epilogue
15841     89/<- %esp 5/r32/ebp
15842     5d/pop-to-ebp
15843     c3/return
15844 
15845 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
15846     # shares code with emit-subx-var-as-rm32
15847     # . prologue
15848     55/push-ebp
15849     89/<- %ebp 4/r32/esp
15850     # . save registers
15851     50/push-eax
15852     51/push-ecx
15853     56/push-esi
15854     # ecx = s
15855     8b/-> *(ebp+0xc) 1/r32/ecx
15856     # var operand/esi: (addr var) = lookup(s->value)
15857     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15858     89/<- %esi 0/r32/eax
15859     # if (operand->register && !s->is-deref?) emit "%__"
15860     {
15861 $emit-subx-call-operand:check-for-register-direct:
15862       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15863       74/jump-if-= break/disp8
15864       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15865       75/jump-if-!= break/disp8
15866 $emit-subx-call-operand:register-direct:
15867       (write-buffered *(ebp+8) " %")
15868       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15869       (write-buffered *(ebp+8) %eax)
15870       e9/jump $emit-subx-call-operand:end/disp32
15871     }
15872     # else if (operand->register && s->is-deref?) emit "*__"
15873     {
15874 $emit-subx-call-operand:check-for-register-indirect:
15875       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15876       74/jump-if-= break/disp8
15877       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15878       74/jump-if-= break/disp8
15879 $emit-subx-call-operand:register-indirect:
15880       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
15881       e9/jump $emit-subx-call-operand:end/disp32
15882     }
15883     # else if (operand->stack-offset) emit "*(ebp+__)"
15884     {
15885       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
15886       74/jump-if-= break/disp8
15887 $emit-subx-call-operand:stack:
15888       (emit-subx-call-operand-stack *(ebp+8) %esi)
15889       e9/jump $emit-subx-call-operand:end/disp32
15890     }
15891     # else if (operand->type == literal) emit "__"
15892     {
15893       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
15894       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
15895       75/jump-if-!= break/disp8
15896 $emit-subx-call-operand:literal:
15897       (write-buffered *(ebp+8) Space)
15898       (lookup *esi *(esi+4))  # Var-name Var-name => eax
15899       (write-buffered *(ebp+8) %eax)
15900     }
15901 $emit-subx-call-operand:end:
15902     # . restore registers
15903     5e/pop-to-esi
15904     59/pop-to-ecx
15905     58/pop-to-eax
15906     # . epilogue
15907     89/<- %esp 5/r32/ebp
15908     5d/pop-to-ebp
15909     c3/return
15910 
15911 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
15912     # . prologue
15913     55/push-ebp
15914     89/<- %ebp 4/r32/esp
15915     # . save registers
15916     50/push-eax
15917     51/push-ecx
15918     56/push-esi
15919     # esi = v
15920     8b/-> *(ebp+0xc) 6/r32/esi
15921     # var size/ecx: int = size-of-deref(v)
15922     (size-of-deref %esi)  # => eax
15923     89/<- %ecx 0/r32/eax
15924     # var reg-name/esi: (addr array byte) = lookup(v->register)
15925     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15926     89/<- %esi 0/r32/eax
15927     # TODO: assert size is a multiple of 4
15928     # var i/eax: int = 0
15929     b8/copy-to-eax 0/imm32
15930     {
15931 $emit-subx-call-operand-register-indirect:loop:
15932       # if (i >= size) break
15933       39/compare %eax 1/r32/ecx
15934       7d/jump-if->= break/disp8
15935       # emit " *(" v->register "+" i ")"
15936       (write-buffered *(ebp+8) " *(")
15937       (write-buffered *(ebp+8) %esi)
15938       (write-buffered *(ebp+8) "+")
15939       (print-int32-buffered *(ebp+8) %eax)
15940       (write-buffered *(ebp+8) ")")
15941       # i += 4
15942       05/add-to-eax 4/imm32
15943       #
15944       eb/jump loop/disp8
15945     }
15946 $emit-subx-call-operand-register-indirect:end:
15947     # . restore registers
15948     5e/pop-to-esi
15949     59/pop-to-ecx
15950     58/pop-to-eax
15951     # . epilogue
15952     89/<- %esp 5/r32/ebp
15953     5d/pop-to-ebp
15954     c3/return
15955 
15956 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
15957     # . prologue
15958     55/push-ebp
15959     89/<- %ebp 4/r32/esp
15960     # . save registers
15961     50/push-eax
15962     51/push-ecx
15963     56/push-esi
15964     # esi = v
15965     8b/-> *(ebp+0xc) 6/r32/esi
15966     # var curr/ecx: int = v->offset
15967     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
15968     # var max/eax: int = v->offset + size-of(v)
15969     (size-of %esi)  # => eax
15970     # TODO: assert size is a multiple of 4
15971     01/add-to %eax 1/r32/ecx
15972     {
15973 $emit-subx-call-operand-stack:loop:
15974       # if (curr >= max) break
15975       39/compare %ecx 0/r32/eax
15976       7d/jump-if->= break/disp8
15977       # emit " *(ebp+" curr ")"
15978       (write-buffered *(ebp+8) " *(ebp+")
15979       (print-int32-buffered *(ebp+8) %ecx)
15980       (write-buffered *(ebp+8) ")")
15981       # i += 4
15982       81 0/subop/add %ecx 4/imm32
15983       #
15984       eb/jump loop/disp8
15985     }
15986 $emit-subx-call-operand-stack:end:
15987     # . restore registers
15988     5e/pop-to-esi
15989     59/pop-to-ecx
15990     58/pop-to-eax
15991     # . epilogue
15992     89/<- %esp 5/r32/ebp
15993     5d/pop-to-ebp
15994     c3/return
15995 
15996 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
15997     # . prologue
15998     55/push-ebp
15999     89/<- %ebp 4/r32/esp
16000     # . save registers
16001     50/push-eax
16002     51/push-ecx
16003     56/push-esi
16004     # ecx = s
16005     8b/-> *(ebp+0xc) 1/r32/ecx
16006     # var operand/esi: (addr var) = lookup(s->value)
16007     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
16008     89/<- %esi 0/r32/eax
16009     # if (operand->register && s->is-deref?) emit "*__"
16010     {
16011 $emit-subx-var-as-rm32:check-for-register-indirect:
16012       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
16013       74/jump-if-= break/disp8
16014       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
16015       74/jump-if-= break/disp8
16016 $emit-subx-var-as-rm32:register-indirect:
16017       (write-buffered *(ebp+8) " *")
16018       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
16019       (write-buffered *(ebp+8) %eax)
16020       e9/jump $emit-subx-var-as-rm32:end/disp32
16021     }
16022     # if (operand->register && !s->is-deref?) emit "%__"
16023     {
16024 $emit-subx-var-as-rm32:check-for-register-direct:
16025       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
16026       74/jump-if-= break/disp8
16027       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
16028       75/jump-if-!= break/disp8
16029 $emit-subx-var-as-rm32:register-direct:
16030       (write-buffered *(ebp+8) " %")
16031       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
16032       (write-buffered *(ebp+8) %eax)
16033       e9/jump $emit-subx-var-as-rm32:end/disp32
16034     }
16035     # else if (operand->stack-offset) emit "*(ebp+__)"
16036     {
16037       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
16038       74/jump-if-= break/disp8
16039 $emit-subx-var-as-rm32:stack:
16040       (write-buffered *(ebp+8) Space)
16041       (write-buffered *(ebp+8) "*(ebp+")
16042       (print-int32-buffered *(ebp+8) *(esi+0x14))  # Var-offset
16043       (write-buffered *(ebp+8) ")")
16044     }
16045 $emit-subx-var-as-rm32:end:
16046     # . restore registers
16047     5e/pop-to-esi
16048     59/pop-to-ecx
16049     58/pop-to-eax
16050     # . epilogue
16051     89/<- %esp 5/r32/ebp
16052     5d/pop-to-ebp
16053     c3/return
16054 
16055 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
16056     # . prologue
16057     55/push-ebp
16058     89/<- %ebp 4/r32/esp
16059     # . save registers
16060     51/push-ecx
16061     # var curr/ecx: (addr primitive) = primitives
16062     8b/-> *(ebp+8) 1/r32/ecx
16063     {
16064 $find-matching-primitive:loop:
16065       # if (curr == null) break
16066       81 7/subop/compare %ecx 0/imm32
16067       74/jump-if-= break/disp8
16068       # if match(curr, stmt) return curr
16069       {
16070         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
16071         3d/compare-eax-and 0/imm32/false
16072         74/jump-if-= break/disp8
16073         89/<- %eax 1/r32/ecx
16074         eb/jump $find-matching-primitive:end/disp8
16075       }
16076 $find-matching-primitive:next-primitive:
16077       # curr = curr->next
16078       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
16079       89/<- %ecx 0/r32/eax
16080       #
16081       e9/jump loop/disp32
16082     }
16083     # return null
16084     b8/copy-to-eax 0/imm32
16085 $find-matching-primitive:end:
16086     # . restore registers
16087     59/pop-to-ecx
16088     # . epilogue
16089     89/<- %esp 5/r32/ebp
16090     5d/pop-to-ebp
16091     c3/return
16092 
16093 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
16094     # A mu stmt matches a primitive if the name matches, all the inout vars
16095     # match, and all the output vars match.
16096     # Vars match if types match and registers match.
16097     # In addition, a stmt output matches a primitive's output if types match
16098     # and the primitive has a wildcard register.
16099     # . prologue
16100     55/push-ebp
16101     89/<- %ebp 4/r32/esp
16102     # . save registers
16103     51/push-ecx
16104     52/push-edx
16105     53/push-ebx
16106     56/push-esi
16107     57/push-edi
16108     # ecx = stmt
16109     8b/-> *(ebp+8) 1/r32/ecx
16110     # edx = primitive
16111     8b/-> *(ebp+0xc) 2/r32/edx
16112     {
16113 $mu-stmt-matches-primitive?:check-name:
16114       # if (primitive->name != stmt->operation) return false
16115       # . var esi: (addr array byte) = lookup(stmt->operation)
16116       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
16117       89/<- %esi 0/r32/eax
16118       # . var edi: (addr array byte) = lookup(primitive->name)
16119       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
16120       89/<- %edi 0/r32/eax
16121       (string-equal? %esi %edi)  # => eax
16122       3d/compare-eax-and 0/imm32/false
16123       75/jump-if-!= break/disp8
16124       b8/copy-to-eax 0/imm32
16125       e9/jump $mu-stmt-matches-primitive?:end/disp32
16126     }
16127     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
16128     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
16129     89/<- %esi 0/r32/eax
16130     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
16131     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
16132     89/<- %edi 0/r32/eax
16133     {
16134 $mu-stmt-matches-primitive?:inouts-loop:
16135       # if (curr == 0 && curr2 == 0) move on to check outputs
16136       {
16137 $mu-stmt-matches-primitive?:check-both-inouts-null:
16138         81 7/subop/compare %esi 0/imm32
16139         75/jump-if-!= break/disp8
16140 $mu-stmt-matches-primitive?:stmt-inout-null:
16141         81 7/subop/compare %edi 0/imm32
16142         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
16143 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
16144         # return false
16145         b8/copy-to-eax 0/imm32/false
16146         e9/jump $mu-stmt-matches-primitive?:end/disp32
16147       }
16148       # if (curr2 == 0) return false
16149       {
16150 $mu-stmt-matches-primitive?:check-prim-inout-null:
16151         81 7/subop/compare %edi 0/imm32
16152         75/jump-if-!= break/disp8
16153 $mu-stmt-matches-primitive?:prim-inout-null:
16154         b8/copy-to-eax 0/imm32/false
16155         e9/jump $mu-stmt-matches-primitive?:end/disp32
16156       }
16157       # if (curr != curr2) return false
16158       {
16159 $mu-stmt-matches-primitive?:check-inouts-match:
16160         (lookup *edi *(edi+4))  # List-value List-value => eax
16161         (operand-matches-primitive? %esi %eax)  # => eax
16162         3d/compare-eax-and 0/imm32/false
16163         75/jump-if-!= break/disp8
16164 $mu-stmt-matches-primitive?:inouts-match:
16165         b8/copy-to-eax 0/imm32/false
16166         e9/jump $mu-stmt-matches-primitive?:end/disp32
16167       }
16168 $mu-stmt-matches-primitive?:next-inout:
16169       # curr = lookup(curr->next)
16170       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
16171       89/<- %esi 0/r32/eax
16172       # curr2 = lookup(curr2->next)
16173       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
16174       89/<- %edi 0/r32/eax
16175       #
16176       e9/jump loop/disp32
16177     }
16178 $mu-stmt-matches-primitive?:check-outputs:
16179     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
16180     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
16181     89/<- %esi 0/r32/eax
16182     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
16183     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
16184     89/<- %edi 0/r32/eax
16185     {
16186 $mu-stmt-matches-primitive?:outputs-loop:
16187       # if (curr == 0) return (curr2 == 0)
16188       {
16189 $mu-stmt-matches-primitive?:check-both-outputs-null:
16190         81 7/subop/compare %esi 0/imm32
16191         75/jump-if-!= break/disp8
16192         {
16193 $mu-stmt-matches-primitive?:stmt-output-null:
16194           81 7/subop/compare %edi 0/imm32
16195           75/jump-if-!= break/disp8
16196 $mu-stmt-matches-primitive?:both-outputs-null:
16197           # return true
16198           b8/copy-to-eax 1/imm32
16199           e9/jump $mu-stmt-matches-primitive?:end/disp32
16200         }
16201 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
16202         # return false
16203         b8/copy-to-eax 0/imm32
16204         e9/jump $mu-stmt-matches-primitive?:end/disp32
16205       }
16206       # if (curr2 == 0) return false
16207       {
16208 $mu-stmt-matches-primitive?:check-prim-output-null:
16209         81 7/subop/compare %edi 0/imm32
16210         75/jump-if-!= break/disp8
16211 $mu-stmt-matches-primitive?:prim-output-is-null:
16212         b8/copy-to-eax 0/imm32
16213         e9/jump $mu-stmt-matches-primitive?:end/disp32
16214       }
16215       # if (curr != curr2) return false
16216       {
16217 $mu-stmt-matches-primitive?:check-outputs-match:
16218         (lookup *edi *(edi+4))  # List-value List-value => eax
16219         (operand-matches-primitive? %esi %eax)  # => eax
16220         3d/compare-eax-and 0/imm32/false
16221         75/jump-if-!= break/disp8
16222 $mu-stmt-matches-primitive?:outputs-match:
16223         b8/copy-to-eax 0/imm32
16224         e9/jump $mu-stmt-matches-primitive?:end/disp32
16225       }
16226 $mu-stmt-matches-primitive?:next-output:
16227       # curr = lookup(curr->next)
16228       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
16229       89/<- %esi 0/r32/eax
16230       # curr2 = lookup(curr2->next)
16231       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
16232       89/<- %edi 0/r32/eax
16233       #
16234       e9/jump loop/disp32
16235     }
16236 $mu-stmt-matches-primitive?:return-true:
16237     b8/copy-to-eax 1/imm32
16238 $mu-stmt-matches-primitive?:end:
16239     # . restore registers
16240     5f/pop-to-edi
16241     5e/pop-to-esi
16242     5b/pop-to-ebx
16243     5a/pop-to-edx
16244     59/pop-to-ecx
16245     # . epilogue
16246     89/<- %esp 5/r32/ebp
16247     5d/pop-to-ebp
16248     c3/return
16249 
16250 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
16251     # . prologue
16252     55/push-ebp
16253     89/<- %ebp 4/r32/esp
16254     # . save registers
16255     51/push-ecx
16256     52/push-edx
16257     53/push-ebx
16258     56/push-esi
16259     57/push-edi
16260     # ecx = s
16261     8b/-> *(ebp+8) 1/r32/ecx
16262     # var var/esi: (addr var) = lookup(s->value)
16263     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
16264     89/<- %esi 0/r32/eax
16265     # edi = prim-var
16266     8b/-> *(ebp+0xc) 7/r32/edi
16267 $operand-matches-primitive?:check-type:
16268     # if (var->type != prim-var->type) return false
16269     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
16270     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
16271     89/<- %ebx 0/r32/eax
16272     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
16273     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
16274     (subx-type-equal? %ebx %eax)  # => eax
16275     3d/compare-eax-and 0/imm32/false
16276     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
16277     {
16278 $operand-matches-primitive?:check-register:
16279       # if prim-var is in memory and var is in register but dereference, match
16280       {
16281         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
16282         0f 85/jump-if-!= break/disp32
16283         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
16284         74/jump-if-= break/disp8
16285         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
16286         74/jump-if-= break/disp8
16287 $operand-matches-primitive?:var-deref-match:
16288         e9/jump $operand-matches-primitive?:return-true/disp32
16289       }
16290       # if prim-var is in register and var is in register but dereference, no match
16291       {
16292         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
16293         0f 84/jump-if-= break/disp32
16294         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
16295         0f 84/jump-if-= break/disp32
16296         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
16297         74/jump-if-= break/disp8
16298 $operand-matches-primitive?:var-deref-no-match:
16299         e9/jump $operand-matches-primitive?:return-false/disp32
16300       }
16301       # return false if var->register doesn't match prim-var->register
16302       {
16303         # if register addresses are equal, it's a match
16304         # var vreg/ebx: (addr array byte) = lookup(var->register)
16305         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
16306         89/<- %ebx 0/r32/eax
16307         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
16308         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
16309         89/<- %ecx 0/r32/eax
16310         # if (vreg == preg) break
16311         39/compare %ecx 3/r32/ebx
16312         74/jump-if-= break/disp8
16313 $operand-matches-primitive?:var-register-no-match:
16314         # if either address is 0, return false
16315         81 7/subop/compare %ebx 0/imm32
16316         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
16317         81 7/subop/compare %ecx 0/imm32
16318         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
16319         # if prim-var->register is wildcard, it's a match
16320         (string-equal? %ecx "*")  # Any-register => eax
16321         3d/compare-eax-and 0/imm32/false
16322         75/jump-if-!= break/disp8
16323 $operand-matches-primitive?:wildcard-no-match:
16324         # if string contents aren't equal, return false
16325         (string-equal? %ecx %ebx)  # => eax
16326         3d/compare-eax-and 0/imm32/false
16327         74/jump-if-= $operand-matches-primitive?:return-false/disp8
16328       }
16329     }
16330 $operand-matches-primitive?:return-true:
16331     b8/copy-to-eax 1/imm32/true
16332     eb/jump $operand-matches-primitive?:end/disp8
16333 $operand-matches-primitive?:return-false:
16334     b8/copy-to-eax 0/imm32/false
16335 $operand-matches-primitive?:end:
16336     # . restore registers
16337     5f/pop-to-edi
16338     5e/pop-to-esi
16339     5b/pop-to-ebx
16340     5a/pop-to-edx
16341     59/pop-to-ecx
16342     # . epilogue
16343     89/<- %esp 5/r32/ebp
16344     5d/pop-to-ebp
16345     c3/return
16346 
16347 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
16348     # . prologue
16349     55/push-ebp
16350     89/<- %ebp 4/r32/esp
16351     # . save registers
16352     51/push-ecx
16353     # var curr/ecx: (handle function) = functions
16354     8b/-> *(ebp+8) 1/r32/ecx
16355     {
16356       # if (curr == null) break
16357       81 7/subop/compare %ecx 0/imm32
16358       74/jump-if-= break/disp8
16359 #?       (write-buffered Stderr "iter\n")
16360 #?       (flush Stderr)
16361       # if match(stmt, curr) return curr
16362       {
16363         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
16364         3d/compare-eax-and 0/imm32/false
16365         74/jump-if-= break/disp8
16366         89/<- %eax 1/r32/ecx
16367         eb/jump $find-matching-function:end/disp8
16368       }
16369       # curr = curr->next
16370       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
16371       89/<- %ecx 0/r32/eax
16372       #
16373       eb/jump loop/disp8
16374     }
16375     # return null
16376     b8/copy-to-eax 0/imm32
16377 $find-matching-function:end:
16378     # . restore registers
16379     59/pop-to-ecx
16380     # . epilogue
16381     89/<- %esp 5/r32/ebp
16382     5d/pop-to-ebp
16383     c3/return
16384 
16385 # Just compare names; user-defined functions don't support overloading yet.
16386 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
16387     # . prologue
16388     55/push-ebp
16389     89/<- %ebp 4/r32/esp
16390     # . save registers
16391     51/push-ecx
16392     # return function->name == stmt->operation
16393     # ecx = lookup(stmt->operation)
16394     8b/-> *(ebp+8) 0/r32/eax
16395     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
16396     89/<- %ecx 0/r32/eax
16397     # eax = lookup(function->name)
16398     8b/-> *(ebp+0xc) 0/r32/eax
16399     (lookup *eax *(eax+4))  # Function-name Function-name => eax
16400     (string-equal? %eax %ecx)  # => eax
16401 $mu-stmt-matches-function?:end:
16402     # . restore registers
16403     59/pop-to-ecx
16404     # . epilogue
16405     89/<- %esp 5/r32/ebp
16406     5d/pop-to-ebp
16407     c3/return
16408 
16409 subx-type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
16410     # . prologue
16411     55/push-ebp
16412     89/<- %ebp 4/r32/esp
16413     # . save registers
16414     51/push-ecx
16415     # var alit/ecx: boolean = is-literal-type?(a)
16416     (is-simple-mu-type? *(ebp+8) 0)  # => eax
16417     89/<- %ecx 0/r32/eax
16418     # var blit/eax: boolean = is-literal-type?(b)
16419     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
16420     # return alit == blit
16421     39/compare %eax 1/r32/ecx
16422     0f 94/set-byte-if-= %al
16423     81 4/subop/and %eax 0xff/imm32
16424 $subx-type-equal?:end:
16425     # . restore registers
16426     59/pop-to-ecx
16427     # . epilogue
16428     89/<- %esp 5/r32/ebp
16429     5d/pop-to-ebp
16430     c3/return
16431 
16432 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
16433     # . prologue
16434     55/push-ebp
16435     89/<- %ebp 4/r32/esp
16436     # . save registers
16437     51/push-ecx
16438     # ecx = n
16439     8b/-> *(ebp+0xc) 1/r32/ecx
16440     # return (a->value == n)
16441     8b/-> *(ebp+8) 0/r32/eax
16442     39/compare *(eax+4) 1/r32/ecx  # Tree-value
16443     0f 94/set-byte-if-= %al
16444     81 4/subop/and %eax 0xff/imm32
16445 $is-simple-mu-type?:end:
16446     # . restore registers
16447     59/pop-to-ecx
16448     # . epilogue
16449     89/<- %esp 5/r32/ebp
16450     5d/pop-to-ebp
16451     c3/return
16452 
16453 test-emit-subx-stmt-primitive:
16454     # Primitive operation on a variable on the stack.
16455     #   increment foo
16456     # =>
16457     #   ff 0/subop/increment *(ebp-8)
16458     #
16459     # There's a variable on the var stack as follows:
16460     #   name: 'foo'
16461     #   type: int
16462     #   stack-offset: -8
16463     #
16464     # There's a primitive with this info:
16465     #   name: 'increment'
16466     #   inouts: int/mem
16467     #   value: 'ff 0/subop/increment'
16468     #
16469     # . prologue
16470     55/push-ebp
16471     89/<- %ebp 4/r32/esp
16472     # setup
16473     (clear-stream _test-output-stream)
16474     (clear-stream $_test-output-buffered-file->buffer)
16475     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
16476 $test-emit-subx-stmt-primitive:initialize-type:
16477     # var type/ecx: (payload tree type-id) = int
16478     68/push 0/imm32/right:null
16479     68/push 0/imm32/right:null
16480     68/push 0/imm32/left:unused
16481     68/push 1/imm32/value:int
16482     68/push 1/imm32/is-atom?:true
16483     68/push 0x11/imm32/alloc-id:fake:payload
16484     89/<- %ecx 4/r32/esp
16485 $test-emit-subx-stmt-primitive:initialize-var:
16486     # var var-foo/ecx: (payload var) = var(type)
16487     68/push 0/imm32/no-register
16488     68/push 0/imm32/no-register
16489     68/push -8/imm32/stack-offset
16490     68/push 1/imm32/block-depth
16491     51/push-ecx/type
16492     68/push 0x11/imm32/alloc-id:fake
16493     68/push 0/imm32/name
16494     68/push 0/imm32/name
16495     68/push 0x11/imm32/alloc-id:fake:payload
16496     89/<- %ecx 4/r32/esp
16497 $test-emit-subx-stmt-primitive:initialize-var-name:
16498     # var-foo->name = "foo"
16499     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16500     (copy-array Heap "foo" %eax)
16501 $test-emit-subx-stmt-primitive:initialize-stmt-var:
16502     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
16503     68/push 0/imm32/is-deref:false
16504     68/push 0/imm32/next
16505     68/push 0/imm32/next
16506     51/push-ecx/var-foo
16507     68/push 0x11/imm32/alloc-id:fake
16508     68/push 0x11/imm32/alloc-id:fake:payload
16509     89/<- %ebx 4/r32/esp
16510 $test-emit-subx-stmt-primitive:initialize-stmt:
16511     # var stmt/esi: (addr statement)
16512     68/push 0/imm32/no-outputs
16513     68/push 0/imm32/no-outputs
16514     53/push-ebx/inouts
16515     68/push 0x11/imm32/alloc-id:fake
16516     68/push 0/imm32/operation
16517     68/push 0/imm32/operation
16518     68/push 1/imm32/tag
16519     89/<- %esi 4/r32/esp
16520 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
16521     # stmt->operation = "increment"
16522     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16523     (copy-array Heap "increment" %eax)
16524 $test-emit-subx-stmt-primitive:initialize-primitive:
16525     # var primitives/ebx: (addr primitive)
16526     68/push 0/imm32/next
16527     68/push 0/imm32/next
16528     68/push 0/imm32/output-is-write-only
16529     68/push 0/imm32/no-disp32
16530     68/push 0/imm32/no-imm32
16531     68/push 0/imm32/no-r32
16532     68/push 1/imm32/rm32-is-first-inout
16533     68/push 0/imm32/subx-name
16534     68/push 0/imm32/subx-name
16535     68/push 0/imm32/no-outputs
16536     68/push 0/imm32/no-outputs
16537     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
16538     68/push 0x11/imm32/alloc-id:fake
16539     68/push 0/imm32/name
16540     68/push 0/imm32/name
16541     89/<- %ebx 4/r32/esp
16542 $test-emit-subx-stmt-primitive:initialize-primitive-name:
16543     # primitives->name = "increment"
16544     (copy-array Heap "increment" %ebx)  # Primitive-name
16545 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
16546     # primitives->subx-name = "ff 0/subop/increment"
16547     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
16548     (copy-array Heap "ff 0/subop/increment" %eax)
16549     # convert
16550     c7 0/subop/copy *Curr-block-depth 0/imm32
16551     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
16552     (flush _test-output-buffered-file)
16553 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16559     # check output
16560     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
16561     # . epilogue
16562     89/<- %esp 5/r32/ebp
16563     5d/pop-to-ebp
16564     c3/return
16565 
16566 test-emit-subx-stmt-primitive-register:
16567     # Primitive operation on a variable in a register.
16568     #   foo <- increment
16569     # =>
16570     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
16571     #
16572     # There's a variable on the var stack as follows:
16573     #   name: 'foo'
16574     #   type: int
16575     #   register: 'eax'
16576     #
16577     # There's a primitive with this info:
16578     #   name: 'increment'
16579     #   out: int/reg
16580     #   value: 'ff 0/subop/increment'
16581     #
16582     # . prologue
16583     55/push-ebp
16584     89/<- %ebp 4/r32/esp
16585     # setup
16586     (clear-stream _test-output-stream)
16587     (clear-stream $_test-output-buffered-file->buffer)
16588 $test-emit-subx-stmt-primitive-register:initialize-type:
16589     # var type/ecx: (payload tree type-id) = int
16590     68/push 0/imm32/right:null
16591     68/push 0/imm32/right:null
16592     68/push 0/imm32/left:unused
16593     68/push 1/imm32/value:int
16594     68/push 1/imm32/is-atom?:true
16595     68/push 0x11/imm32/alloc-id:fake:payload
16596     89/<- %ecx 4/r32/esp
16597 $test-emit-subx-stmt-primitive-register:initialize-var:
16598     # var var-foo/ecx: (payload var)
16599     68/push 0/imm32/register
16600     68/push 0/imm32/register
16601     68/push 0/imm32/no-stack-offset
16602     68/push 1/imm32/block-depth
16603     51/push-ecx
16604     68/push 0x11/imm32/alloc-id:fake
16605     68/push 0/imm32/name
16606     68/push 0/imm32/name
16607     68/push 0x11/imm32/alloc-id:fake:payload
16608     89/<- %ecx 4/r32/esp
16609 $test-emit-subx-stmt-primitive-register:initialize-var-name:
16610     # var-foo->name = "foo"
16611     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16612     (copy-array Heap "foo" %eax)
16613 $test-emit-subx-stmt-primitive-register:initialize-var-register:
16614     # var-foo->register = "eax"
16615     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16616     (copy-array Heap "eax" %eax)
16617 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
16618     # var operand/ebx: (payload stmt-var)
16619     68/push 0/imm32/is-deref:false
16620     68/push 0/imm32/next
16621     68/push 0/imm32/next
16622     51/push-ecx/var-foo
16623     68/push 0x11/imm32/alloc-id:fake
16624     68/push 0x11/imm32/alloc-id:fake:payload
16625     89/<- %ebx 4/r32/esp
16626 $test-emit-subx-stmt-primitive-register:initialize-stmt:
16627     # var stmt/esi: (addr statement)
16628     53/push-ebx/outputs
16629     68/push 0x11/imm32/alloc-id:fake
16630     68/push 0/imm32/no-inouts
16631     68/push 0/imm32/no-inouts
16632     68/push 0/imm32/operation
16633     68/push 0/imm32/operation
16634     68/push 1/imm32
16635     89/<- %esi 4/r32/esp
16636 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
16637     # stmt->operation = "increment"
16638     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16639     (copy-array Heap "increment" %eax)
16640 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
16641     # var formal-var/ebx: (payload var)
16642     68/push 0/imm32/register
16643     68/push 0/imm32/register
16644     68/push 0/imm32/no-stack-offset
16645     68/push 1/imm32/block-depth
16646     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
16647     68/push 0x11/imm32/alloc-id:fake
16648     68/push 0/imm32/name
16649     68/push 0/imm32/name
16650     68/push 0x11/imm32/alloc-id:fake:payload
16651     89/<- %ebx 4/r32/esp
16652 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
16653     # formal-var->name = "dummy"
16654     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
16655     (copy-array Heap "dummy" %eax)
16656 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
16657     # formal-var->register = "*"
16658     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
16659     (copy-array Heap "*" %eax)  # Any-register
16660 $test-emit-subx-stmt-primitive-register:initialize-var-list:
16661     # var formal-outputs/ebx: (payload list var)
16662     68/push 0/imm32/next
16663     68/push 0/imm32/next
16664     53/push-ebx/formal-var
16665     68/push 0x11/imm32/alloc-id:fake
16666     68/push 0x11/imm32/alloc-id:fake:payload
16667     89/<- %ebx 4/r32/esp
16668 $test-emit-subx-stmt-primitive-register:initialize-primitive:
16669     # var primitives/ebx: (addr primitive)
16670     68/push 0/imm32/next
16671     68/push 0/imm32/next
16672     68/push 0/imm32/output-is-write-only
16673     68/push 0/imm32/no-disp32
16674     68/push 0/imm32/no-imm32
16675     68/push 0/imm32/no-r32
16676     68/push 3/imm32/rm32-is-first-output
16677     68/push 0/imm32/subx-name
16678     68/push 0/imm32/subx-name
16679     53/push-ebx/outputs
16680     68/push 0x11/imm32/alloc-id:fake
16681     68/push 0/imm32/no-inouts
16682     68/push 0/imm32/no-inouts
16683     68/push 0/imm32/name
16684     68/push 0/imm32/name
16685     89/<- %ebx 4/r32/esp
16686 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
16687     # primitives->name = "increment"
16688     (copy-array Heap "increment" %ebx)  # Primitive-name
16689 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
16690     # primitives->subx-name = "ff 0/subop/increment"
16691     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
16692     (copy-array Heap "ff 0/subop/increment" %eax)
16693     # convert
16694     c7 0/subop/copy *Curr-block-depth 0/imm32
16695     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
16696     (flush _test-output-buffered-file)
16697 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16703     # check output
16704     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
16705     # . epilogue
16706     89/<- %esp 5/r32/ebp
16707     5d/pop-to-ebp
16708     c3/return
16709 
16710 test-emit-subx-stmt-select-primitive:
16711     # Select the right primitive between overloads.
16712     #   foo <- increment
16713     # =>
16714     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
16715     #
16716     # There's a variable on the var stack as follows:
16717     #   name: 'foo'
16718     #   type: int
16719     #   register: 'eax'
16720     #
16721     # There's two primitives, as follows:
16722     #   - name: 'increment'
16723     #     out: int/reg
16724     #     value: 'ff 0/subop/increment'
16725     #   - name: 'increment'
16726     #     inout: int/mem
16727     #     value: 'ff 0/subop/increment'
16728     #
16729     # . prologue
16730     55/push-ebp
16731     89/<- %ebp 4/r32/esp
16732     # setup
16733     (clear-stream _test-output-stream)
16734     (clear-stream $_test-output-buffered-file->buffer)
16735 $test-emit-subx-stmt-select-primitive:initialize-type:
16736     # var type/ecx: (payload tree type-id) = int
16737     68/push 0/imm32/right:null
16738     68/push 0/imm32/right:null
16739     68/push 0/imm32/left:unused
16740     68/push 1/imm32/value:int
16741     68/push 1/imm32/is-atom?:true
16742     68/push 0x11/imm32/alloc-id:fake:payload
16743     89/<- %ecx 4/r32/esp
16744 $test-emit-subx-stmt-select-primitive:initialize-var:
16745     # var var-foo/ecx: (payload var)
16746     68/push 0/imm32/register
16747     68/push 0/imm32/register
16748     68/push 0/imm32/no-stack-offset
16749     68/push 1/imm32/block-depth
16750     51/push-ecx
16751     68/push 0x11/imm32/alloc-id:fake
16752     68/push 0/imm32/name
16753     68/push 0/imm32/name
16754     68/push 0x11/imm32/alloc-id:fake:payload
16755     89/<- %ecx 4/r32/esp
16756 $test-emit-subx-stmt-select-primitive:initialize-var-name:
16757     # var-foo->name = "foo"
16758     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16759     (copy-array Heap "foo" %eax)
16760 $test-emit-subx-stmt-select-primitive:initialize-var-register:
16761     # var-foo->register = "eax"
16762     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16763     (copy-array Heap "eax" %eax)
16764 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
16765     # var operand/ebx: (payload stmt-var)
16766     68/push 0/imm32/is-deref:false
16767     68/push 0/imm32/next
16768     68/push 0/imm32/next
16769     51/push-ecx/var-foo
16770     68/push 0x11/imm32/alloc-id:fake
16771     68/push 0x11/imm32/alloc-id:fake:payload
16772     89/<- %ebx 4/r32/esp
16773 $test-emit-subx-stmt-select-primitive:initialize-stmt:
16774     # var stmt/esi: (addr statement)
16775     53/push-ebx/outputs
16776     68/push 0x11/imm32/alloc-id:fake
16777     68/push 0/imm32/no-inouts
16778     68/push 0/imm32/no-inouts
16779     68/push 0/imm32/operation
16780     68/push 0/imm32/operation
16781     68/push 1/imm32
16782     89/<- %esi 4/r32/esp
16783 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
16784     # stmt->operation = "increment"
16785     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16786     (copy-array Heap "increment" %eax)
16787 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
16788     # var formal-var/ebx: (payload var)
16789     68/push 0/imm32/register
16790     68/push 0/imm32/register
16791     68/push 0/imm32/no-stack-offset
16792     68/push 1/imm32/block-depth
16793     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
16794     68/push 0x11/imm32/alloc-id:fake
16795     68/push 0/imm32/name
16796     68/push 0/imm32/name
16797     68/push 0x11/imm32/alloc-id:fake:payload
16798     89/<- %ebx 4/r32/esp
16799 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
16800     # formal-var->name = "dummy"
16801     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
16802     (copy-array Heap "dummy" %eax)
16803 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
16804     # formal-var->register = "*"
16805     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
16806     (copy-array Heap "*" %eax)  # Any-register
16807 $test-emit-subx-stmt-select-primitive:initialize-var-list:
16808     # var formal-outputs/ebx: (payload list var)
16809     68/push 0/imm32/next
16810     68/push 0/imm32/next
16811     53/push-ebx/formal-var
16812     68/push 0x11/imm32/alloc-id:fake
16813     68/push 0x11/imm32/alloc-id:fake:payload
16814     89/<- %ebx 4/r32/esp
16815 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
16816     # var primitive2/edi: (payload primitive)
16817     68/push 0/imm32/next
16818     68/push 0/imm32/next
16819     68/push 0/imm32/output-is-write-only
16820     68/push 0/imm32/no-disp32
16821     68/push 0/imm32/no-imm32
16822     68/push 0/imm32/no-r32
16823     68/push 3/imm32/rm32-is-first-output
16824     68/push 0/imm32/subx-name
16825     68/push 0/imm32/subx-name
16826     53/push-ebx/outputs
16827     68/push 0x11/imm32/alloc-id:fake
16828     68/push 0/imm32/no-inouts
16829     68/push 0/imm32/no-inouts
16830     68/push 0/imm32/name
16831     68/push 0/imm32/name
16832     68/push 0x11/imm32/alloc-id:fake:payload
16833     89/<- %edi 4/r32/esp
16834 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
16835     # primitives->name = "increment"
16836     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
16837     (copy-array Heap "increment" %eax)
16838 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
16839     # primitives->subx-name = "ff 0/subop/increment"
16840     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
16841     (copy-array Heap "ff 0/subop/increment" %eax)
16842 $test-emit-subx-stmt-select-primitive:initialize-primitive:
16843     # var primitives/ebx: (addr primitive)
16844     57/push-edi
16845     68/push 0x11/imm32/alloc-id:fake
16846     68/push 0/imm32/output-is-write-only
16847     68/push 0/imm32/no-disp32
16848     68/push 0/imm32/no-imm32
16849     68/push 0/imm32/no-r32
16850     68/push 1/imm32/rm32-is-first-inout
16851     68/push 0/imm32/subx-name
16852     68/push 0/imm32/subx-name
16853     68/push 0/imm32/no-outputs
16854     68/push 0/imm32/no-outputs
16855     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
16856     68/push 0x11/imm32/alloc-id:fake
16857     68/push 0/imm32/name
16858     68/push 0/imm32/name
16859     89/<- %ebx 4/r32/esp
16860 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
16861     # primitives->name = "increment"
16862     (copy-array Heap "increment" %ebx)  # Primitive-name
16863 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
16864     # primitives->subx-name = "ff 0/subop/increment"
16865     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
16866     (copy-array Heap "ff 0/subop/increment" %eax)
16867     # convert
16868     c7 0/subop/copy *Curr-block-depth 0/imm32
16869     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
16870     (flush _test-output-buffered-file)
16871 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16877     # check output
16878     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
16879     # . epilogue
16880     89/<- %esp 5/r32/ebp
16881     5d/pop-to-ebp
16882     c3/return
16883 
16884 test-emit-subx-stmt-select-primitive-2:
16885     # Select the right primitive between overloads.
16886     #   increment foo
16887     # =>
16888     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
16889     #
16890     # There's a variable on the var stack as follows:
16891     #   name: 'foo'
16892     #   type: int
16893     #   register: 'eax'
16894     #
16895     # There's two primitives, as follows:
16896     #   - name: 'increment'
16897     #     out: int/reg
16898     #     value: 'ff 0/subop/increment'
16899     #   - name: 'increment'
16900     #     inout: int/mem
16901     #     value: 'ff 0/subop/increment'
16902     #
16903     # . prologue
16904     55/push-ebp
16905     89/<- %ebp 4/r32/esp
16906     # setup
16907     (clear-stream _test-output-stream)
16908     (clear-stream $_test-output-buffered-file->buffer)
16909 $test-emit-subx-stmt-select-primitive-2:initialize-type:
16910     # var type/ecx: (payload tree type-id) = int
16911     68/push 0/imm32/right:null
16912     68/push 0/imm32/right:null
16913     68/push 0/imm32/left:unused
16914     68/push 1/imm32/value:int
16915     68/push 1/imm32/is-atom?:true
16916     68/push 0x11/imm32/alloc-id:fake:payload
16917     89/<- %ecx 4/r32/esp
16918 $test-emit-subx-stmt-select-primitive-2:initialize-var:
16919     # var var-foo/ecx: (payload var)
16920     68/push 0/imm32/register
16921     68/push 0/imm32/register
16922     68/push 0/imm32/no-stack-offset
16923     68/push 1/imm32/block-depth
16924     51/push-ecx
16925     68/push 0x11/imm32/alloc-id:fake
16926     68/push 0/imm32/name
16927     68/push 0/imm32/name
16928     68/push 0x11/imm32/alloc-id:fake:payload
16929     89/<- %ecx 4/r32/esp
16930 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
16931     # var-foo->name = "foo"
16932     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16933     (copy-array Heap "foo" %eax)
16934 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
16935     # var-foo->register = "eax"
16936     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16937     (copy-array Heap "eax" %eax)
16938 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
16939     # var operand/ebx: (payload stmt-var)
16940     68/push 0/imm32/is-deref:false
16941     68/push 0/imm32/next
16942     68/push 0/imm32/next
16943     51/push-ecx/var-foo
16944     68/push 0x11/imm32/alloc-id:fake
16945     68/push 0x11/imm32/alloc-id:fake:payload
16946     89/<- %ebx 4/r32/esp
16947 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
16948     # var stmt/esi: (addr statement)
16949     68/push 0/imm32/no-outputs
16950     68/push 0/imm32/no-outputs
16951     53/push-ebx/inouts
16952     68/push 0x11/imm32/alloc-id:fake
16953     68/push 0/imm32/operation
16954     68/push 0/imm32/operation
16955     68/push 1/imm32
16956     89/<- %esi 4/r32/esp
16957 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
16958     # stmt->operation = "increment"
16959     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16960     (copy-array Heap "increment" %eax)
16961 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
16962     # var formal-var/ebx: (payload var)
16963     68/push 0/imm32/register
16964     68/push 0/imm32/register
16965     68/push 0/imm32/no-stack-offset
16966     68/push 1/imm32/block-depth
16967     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
16968     68/push 0x11/imm32/alloc-id:fake
16969     68/push 0/imm32/name
16970     68/push 0/imm32/name
16971     68/push 0x11/imm32/alloc-id:fake:payload
16972     89/<- %ebx 4/r32/esp
16973 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
16974     # formal-var->name = "dummy"
16975     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
16976     (copy-array Heap "dummy" %eax)
16977 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
16978     # formal-var->register = "*"
16979     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
16980     (copy-array Heap "*" %eax)  # Any-register
16981 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
16982     # var formal-outputs/ebx: (payload list stmt-var)
16983     68/push 0/imm32/next
16984     68/push 0/imm32/next
16985     53/push-ebx/formal-var
16986     68/push 0x11/imm32/alloc-id:fake
16987     68/push 0x11/imm32/alloc-id:fake:payload
16988     89/<- %ebx 4/r32/esp
16989 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
16990     # var primitive2/edi: (payload primitive)
16991     68/push 0/imm32/next
16992     68/push 0/imm32/next
16993     68/push 0/imm32/output-is-write-only
16994     68/push 0/imm32/no-disp32
16995     68/push 0/imm32/no-imm32
16996     68/push 0/imm32/no-r32
16997     68/push 3/imm32/rm32-is-first-output
16998     68/push 0/imm32/subx-name
16999     68/push 0/imm32/subx-name
17000     53/push-ebx/outputs
17001     68/push 0x11/imm32/alloc-id:fake
17002     68/push 0/imm32/no-inouts
17003     68/push 0/imm32/no-inouts
17004     68/push 0/imm32/name
17005     68/push 0/imm32/name
17006     68/push 0x11/imm32/alloc-id:fake:payload
17007     89/<- %edi 4/r32/esp
17008 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
17009     # primitives->name = "increment"
17010     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
17011     (copy-array Heap "increment" %eax)
17012 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
17013     # primitives->subx-name = "ff 0/subop/increment"
17014     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
17015     (copy-array Heap "ff 0/subop/increment" %eax)
17016 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
17017     # var primitives/ebx: (addr primitive)
17018     57/push-edi
17019     68/push 0x11/imm32/alloc-id:fake
17020     68/push 0/imm32/output-is-write-only
17021     68/push 0/imm32/no-disp32
17022     68/push 0/imm32/no-imm32
17023     68/push 0/imm32/no-r32
17024     68/push 1/imm32/rm32-is-first-inout
17025     68/push 0/imm32/subx-name
17026     68/push 0/imm32/subx-name
17027     68/push 0/imm32/no-outputs
17028     68/push 0/imm32/no-outputs
17029     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
17030     68/push 0x11/imm32/alloc-id:fake
17031     68/push 0/imm32/name
17032     68/push 0/imm32/name
17033     89/<- %ebx 4/r32/esp
17034 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
17035     # primitives->name = "increment"
17036     (copy-array Heap "increment" %ebx)  # Primitive-name
17037 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
17038     # primitives->subx-name = "ff 0/subop/increment"
17039     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
17040     (copy-array Heap "ff 0/subop/increment" %eax)
17041     # convert
17042     c7 0/subop/copy *Curr-block-depth 0/imm32
17043     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
17044     (flush _test-output-buffered-file)
17045 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17051     # check output
17052     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
17053     # . epilogue
17054     89/<- %esp 5/r32/ebp
17055     5d/pop-to-ebp
17056     c3/return
17057 
17058 test-increment-register:
17059     # Select the right register between overloads.
17060     #   foo <- increment
17061     # =>
17062     #   50/increment-eax
17063     #
17064     # There's a variable on the var stack as follows:
17065     #   name: 'foo'
17066     #   type: int
17067     #   register: 'eax'
17068     #
17069     # Primitives are the global definitions.
17070     #
17071     # . prologue
17072     55/push-ebp
17073     89/<- %ebp 4/r32/esp
17074     # setup
17075     (clear-stream _test-output-stream)
17076     (clear-stream $_test-output-buffered-file->buffer)
17077 $test-increment-register:initialize-type:
17078     # var type/ecx: (payload tree type-id) = int
17079     68/push 0/imm32/right:null
17080     68/push 0/imm32/right:null
17081     68/push 0/imm32/left:unused
17082     68/push 1/imm32/value:int
17083     68/push 1/imm32/is-atom?:true
17084     68/push 0x11/imm32/alloc-id:fake:payload
17085     89/<- %ecx 4/r32/esp
17086 $test-increment-register:initialize-var:
17087     # var var-foo/ecx: (payload var)
17088     68/push 0/imm32/register
17089     68/push 0/imm32/register
17090     68/push 0/imm32/no-stack-offset
17091     68/push 1/imm32/block-depth
17092     51/push-ecx
17093     68/push 0x11/imm32/alloc-id:fake
17094     68/push 0/imm32/name
17095     68/push 0/imm32/name
17096     68/push 0x11/imm32/alloc-id:fake:payload
17097     89/<- %ecx 4/r32/esp
17098 $test-increment-register:initialize-var-name:
17099     # var-foo->name = "foo"
17100     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17101     (copy-array Heap "foo" %eax)
17102 $test-increment-register:initialize-var-register:
17103     # var-foo->register = "eax"
17104     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17105     (copy-array Heap "eax" %eax)
17106 $test-increment-register:initialize-stmt-var:
17107     # var operand/ebx: (payload stmt-var)
17108     68/push 0/imm32/is-deref:false
17109     68/push 0/imm32/next
17110     68/push 0/imm32/next
17111     51/push-ecx/var-foo
17112     68/push 0x11/imm32/alloc-id:fake
17113     68/push 0x11/imm32/alloc-id:fake:payload
17114     89/<- %ebx 4/r32/esp
17115 $test-increment-register:initialize-stmt:
17116     # var stmt/esi: (addr statement)
17117     53/push-ebx/outputs
17118     68/push 0x11/imm32/alloc-id:fake
17119     68/push 0/imm32/no-inouts
17120     68/push 0/imm32/no-inouts
17121     68/push 0/imm32/operation
17122     68/push 0/imm32/operation
17123     68/push 1/imm32
17124     89/<- %esi 4/r32/esp
17125 $test-increment-register:initialize-stmt-operation:
17126     # stmt->operation = "increment"
17127     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17128     (copy-array Heap "increment" %eax)
17129     # convert
17130     c7 0/subop/copy *Curr-block-depth 0/imm32
17131     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17132     (flush _test-output-buffered-file)
17133 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17139     # check output
17140     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
17141     # . epilogue
17142     89/<- %esp 5/r32/ebp
17143     5d/pop-to-ebp
17144     c3/return
17145 
17146 test-add-reg-to-reg:
17147     #   var1/reg <- add var2/reg
17148     # =>
17149     #   01/add-to %var1 var2
17150     #
17151     # . prologue
17152     55/push-ebp
17153     89/<- %ebp 4/r32/esp
17154     # setup
17155     (clear-stream _test-output-stream)
17156     (clear-stream $_test-output-buffered-file->buffer)
17157 $test-add-reg-to-reg:initialize-type:
17158     # var type/ecx: (payload tree type-id) = int
17159     68/push 0/imm32/right:null
17160     68/push 0/imm32/right:null
17161     68/push 0/imm32/left:unused
17162     68/push 1/imm32/value:int
17163     68/push 1/imm32/is-atom?:true
17164     68/push 0x11/imm32/alloc-id:fake:payload
17165     89/<- %ecx 4/r32/esp
17166 $test-add-reg-to-reg:initialize-var1:
17167     # var var1/ecx: (payload var)
17168     68/push 0/imm32/register
17169     68/push 0/imm32/register
17170     68/push 0/imm32/no-stack-offset
17171     68/push 1/imm32/block-depth
17172     51/push-ecx
17173     68/push 0x11/imm32/alloc-id:fake
17174     68/push 0/imm32/name
17175     68/push 0/imm32/name
17176     68/push 0x11/imm32/alloc-id:fake:payload
17177     89/<- %ecx 4/r32/esp
17178 $test-add-reg-to-reg:initialize-var1-name:
17179     # var1->name = "var1"
17180     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17181     (copy-array Heap "var1" %eax)
17182 $test-add-reg-to-reg:initialize-var1-register:
17183     # var1->register = "eax"
17184     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17185     (copy-array Heap "eax" %eax)
17186 $test-add-reg-to-reg:initialize-var2:
17187     # var var2/edx: (payload var)
17188     68/push 0/imm32/register
17189     68/push 0/imm32/register
17190     68/push 0/imm32/no-stack-offset
17191     68/push 1/imm32/block-depth
17192     ff 6/subop/push *(ecx+0x10)
17193     68/push 0x11/imm32/alloc-id:fake
17194     68/push 0/imm32/name
17195     68/push 0/imm32/name
17196     68/push 0x11/imm32/alloc-id:fake:payload
17197     89/<- %edx 4/r32/esp
17198 $test-add-reg-to-reg:initialize-var2-name:
17199     # var2->name = "var2"
17200     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17201     (copy-array Heap "var2" %eax)
17202 $test-add-reg-to-reg:initialize-var2-register:
17203     # var2->register = "ecx"
17204     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17205     (copy-array Heap "ecx" %eax)
17206 $test-add-reg-to-reg:initialize-inouts:
17207     # var inouts/esi: (payload stmt-var) = [var2]
17208     68/push 0/imm32/is-deref:false
17209     68/push 0/imm32/next
17210     68/push 0/imm32/next
17211     52/push-edx/var2
17212     68/push 0x11/imm32/alloc-id:fake
17213     68/push 0x11/imm32/alloc-id:fake:payload
17214     89/<- %esi 4/r32/esp
17215 $test-add-reg-to-reg:initialize-outputs:
17216     # var outputs/edi: (payload stmt-var) = [var1]
17217     68/push 0/imm32/is-deref:false
17218     68/push 0/imm32/next
17219     68/push 0/imm32/next
17220     51/push-ecx/var1
17221     68/push 0x11/imm32/alloc-id:fake
17222     68/push 0x11/imm32/alloc-id:fake:payload
17223     89/<- %edi 4/r32/esp
17224 $test-add-reg-to-reg:initialize-stmt:
17225     # var stmt/esi: (addr statement)
17226     68/push 0/imm32/next
17227     68/push 0/imm32/next
17228     57/push-edi/outputs
17229     68/push 0x11/imm32/alloc-id:fake
17230     56/push-esi/inouts
17231     68/push 0x11/imm32/alloc-id:fake
17232     68/push 0/imm32/operation
17233     68/push 0/imm32/operation
17234     68/push 1/imm32/tag:stmt1
17235     89/<- %esi 4/r32/esp
17236 $test-add-reg-to-reg:initialize-stmt-operation:
17237     # stmt->operation = "add"
17238     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17239     (copy-array Heap "add" %eax)
17240     # convert
17241     c7 0/subop/copy *Curr-block-depth 0/imm32
17242     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17243     (flush _test-output-buffered-file)
17244 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17250     # check output
17251     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
17252     # . epilogue
17253     89/<- %esp 5/r32/ebp
17254     5d/pop-to-ebp
17255     c3/return
17256 
17257 test-add-reg-to-mem:
17258     #   add-to var1 var2/reg
17259     # =>
17260     #   01/add-to *(ebp+__) var2
17261     #
17262     # . prologue
17263     55/push-ebp
17264     89/<- %ebp 4/r32/esp
17265     # setup
17266     (clear-stream _test-output-stream)
17267     (clear-stream $_test-output-buffered-file->buffer)
17268 $test-add-reg-to-mem:initialize-type:
17269     # var type/ecx: (payload tree type-id) = int
17270     68/push 0/imm32/right:null
17271     68/push 0/imm32/right:null
17272     68/push 0/imm32/left:unused
17273     68/push 1/imm32/value:int
17274     68/push 1/imm32/is-atom?:true
17275     68/push 0x11/imm32/alloc-id:fake:payload
17276     89/<- %ecx 4/r32/esp
17277 $test-add-reg-to-mem:initialize-var1:
17278     # var var1/ecx: (payload var)
17279     68/push 0/imm32/register
17280     68/push 0/imm32/register
17281     68/push 8/imm32/stack-offset
17282     68/push 1/imm32/block-depth
17283     51/push-ecx
17284     68/push 0x11/imm32/alloc-id:fake
17285     68/push 0/imm32/name
17286     68/push 0/imm32/name
17287     68/push 0x11/imm32/alloc-id:fake:payload
17288     89/<- %ecx 4/r32/esp
17289 $test-add-reg-to-mem:initialize-var1-name:
17290     # var1->name = "var1"
17291     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17292     (copy-array Heap "var1" %eax)
17293 $test-add-reg-to-mem:initialize-var2:
17294     # var var2/edx: (payload var)
17295     68/push 0/imm32/register
17296     68/push 0/imm32/register
17297     68/push 0/imm32/no-stack-offset
17298     68/push 1/imm32/block-depth
17299     ff 6/subop/push *(ecx+0x10)
17300     68/push 0x11/imm32/alloc-id:fake
17301     68/push 0/imm32/name
17302     68/push 0/imm32/name
17303     68/push 0x11/imm32/alloc-id:fake:payload
17304     89/<- %edx 4/r32/esp
17305 $test-add-reg-to-mem:initialize-var2-name:
17306     # var2->name = "var2"
17307     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17308     (copy-array Heap "var2" %eax)
17309 $test-add-reg-to-mem:initialize-var2-register:
17310     # var2->register = "ecx"
17311     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17312     (copy-array Heap "ecx" %eax)
17313 $test-add-reg-to-mem:initialize-inouts:
17314     # var inouts/esi: (payload stmt-var) = [var2]
17315     68/push 0/imm32/is-deref:false
17316     68/push 0/imm32/next
17317     68/push 0/imm32/next
17318     52/push-edx/var2
17319     68/push 0x11/imm32/alloc-id:fake
17320     68/push 0x11/imm32/alloc-id:fake:payload
17321     89/<- %esi 4/r32/esp
17322     # inouts = [var1, var2]
17323     68/push 0/imm32/is-deref:false
17324     56/push-esi/next
17325     68/push 0x11/imm32/alloc-id:fake
17326     51/push-ecx/var1
17327     68/push 0x11/imm32/alloc-id:fake
17328     68/push 0x11/imm32/alloc-id:fake:payload
17329     89/<- %esi 4/r32/esp
17330 $test-add-reg-to-mem:initialize-stmt:
17331     # var stmt/esi: (addr statement)
17332     68/push 0/imm32/next
17333     68/push 0/imm32/next
17334     68/push 0/imm32/outputs
17335     68/push 0/imm32/outputs
17336     56/push-esi/inouts
17337     68/push 0x11/imm32/alloc-id:fake
17338     68/push 0/imm32/operation
17339     68/push 0/imm32/operation
17340     68/push 1/imm32/tag:stmt1
17341     89/<- %esi 4/r32/esp
17342 $test-add-reg-to-mem:initialize-stmt-operation:
17343     # stmt->operation = "add-to"
17344     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17345     (copy-array Heap "add-to" %eax)
17346     # convert
17347     c7 0/subop/copy *Curr-block-depth 0/imm32
17348     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17349     (flush _test-output-buffered-file)
17350 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17356     # check output
17357     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
17358     # . epilogue
17359     89/<- %esp 5/r32/ebp
17360     5d/pop-to-ebp
17361     c3/return
17362 
17363 test-add-mem-to-reg:
17364     #   var1/reg <- add var2
17365     # =>
17366     #   03/add *(ebp+__) var1
17367     #
17368     # . prologue
17369     55/push-ebp
17370     89/<- %ebp 4/r32/esp
17371     # setup
17372     (clear-stream _test-output-stream)
17373     (clear-stream $_test-output-buffered-file->buffer)
17374 $test-add-mem-to-reg:initialize-type:
17375     # var type/ecx: (payload tree type-id) = int
17376     68/push 0/imm32/right:null
17377     68/push 0/imm32/right:null
17378     68/push 0/imm32/left:unused
17379     68/push 1/imm32/value:int
17380     68/push 1/imm32/is-atom?:true
17381     68/push 0x11/imm32/alloc-id:fake:payload
17382     89/<- %ecx 4/r32/esp
17383 $test-add-mem-to-reg:initialize-var:
17384     # var var1/ecx: (payload var)
17385     68/push 0/imm32/register
17386     68/push 0/imm32/register
17387     68/push 0/imm32/no-stack-offset
17388     68/push 1/imm32/block-depth
17389     51/push-ecx
17390     68/push 0x11/imm32/alloc-id:fake
17391     68/push 0/imm32/name
17392     68/push 0/imm32/name
17393     68/push 0x11/imm32/alloc-id:fake:payload
17394     89/<- %ecx 4/r32/esp
17395 $test-add-mem-to-reg:initialize-var-name:
17396     # var1->name = "foo"
17397     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17398     (copy-array Heap "var1" %eax)
17399 $test-add-mem-to-reg:initialize-var-register:
17400     # var1->register = "eax"
17401     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17402     (copy-array Heap "eax" %eax)
17403 $test-add-mem-to-reg:initialize-var2:
17404     # var var2/edx: (payload var)
17405     68/push 0/imm32/register
17406     68/push 0/imm32/register
17407     68/push 8/imm32/stack-offset
17408     68/push 1/imm32/block-depth
17409     ff 6/subop/push *(ecx+0x10)
17410     68/push 0x11/imm32/alloc-id:fake
17411     68/push 0/imm32/name
17412     68/push 0/imm32/name
17413     68/push 0x11/imm32/alloc-id:fake:payload
17414     89/<- %edx 4/r32/esp
17415 $test-add-mem-to-reg:initialize-var2-name:
17416     # var2->name = "var2"
17417     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17418     (copy-array Heap "var2" %eax)
17419 $test-add-mem-to-reg:initialize-inouts:
17420     # var inouts/esi: (payload stmt-var) = [var2]
17421     68/push 0/imm32/is-deref:false
17422     68/push 0/imm32/next
17423     68/push 0/imm32/next
17424     52/push-edx/var2
17425     68/push 0x11/imm32/alloc-id:fake
17426     68/push 0x11/imm32/alloc-id:fake:payload
17427     89/<- %esi 4/r32/esp
17428 $test-add-mem-to-reg:initialize-outputs:
17429     # var outputs/edi: (payload stmt-var) = [var1]
17430     68/push 0/imm32/is-deref:false
17431     68/push 0/imm32/next
17432     68/push 0/imm32/next
17433     51/push-ecx/var1
17434     68/push 0x11/imm32/alloc-id:fake
17435     68/push 0x11/imm32/alloc-id:fake:payload
17436     89/<- %edi 4/r32/esp
17437 $test-add-mem-to-reg:initialize-stmt:
17438     # var stmt/esi: (addr statement)
17439     68/push 0/imm32/next
17440     68/push 0/imm32/next
17441     57/push-edi/outputs
17442     68/push 0x11/imm32/alloc-id:fake
17443     56/push-esi/inouts
17444     68/push 0x11/imm32/alloc-id:fake
17445     68/push 0/imm32/operation
17446     68/push 0/imm32/operation
17447     68/push 1/imm32/tag:stmt1
17448     89/<- %esi 4/r32/esp
17449 $test-add-mem-to-reg:initialize-stmt-operation:
17450     # stmt->operation = "add"
17451     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17452     (copy-array Heap "add" %eax)
17453     # convert
17454     c7 0/subop/copy *Curr-block-depth 0/imm32
17455     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17456     (flush _test-output-buffered-file)
17457 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17463     # check output
17464     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
17465     # . epilogue
17466     89/<- %esp 5/r32/ebp
17467     5d/pop-to-ebp
17468     c3/return
17469 
17470 test-add-literal-to-eax:
17471     #   var1/eax <- add 0x34
17472     # =>
17473     #   05/add-to-eax 0x34/imm32
17474     #
17475     # . prologue
17476     55/push-ebp
17477     89/<- %ebp 4/r32/esp
17478     # setup
17479     (clear-stream _test-output-stream)
17480     (clear-stream $_test-output-buffered-file->buffer)
17481 $test-add-literal-to-eax:initialize-var-type:
17482     # var type/ecx: (payload tree type-id) = int
17483     68/push 0/imm32/right:null
17484     68/push 0/imm32/right:null
17485     68/push 0/imm32/left:unused
17486     68/push 1/imm32/value:int
17487     68/push 1/imm32/is-atom?:true
17488     68/push 0x11/imm32/alloc-id:fake:payload
17489     89/<- %ecx 4/r32/esp
17490 $test-add-literal-to-eax:initialize-var:
17491     # var v/ecx: (payload var)
17492     68/push 0/imm32/register
17493     68/push 0/imm32/register
17494     68/push 0/imm32/no-stack-offset
17495     68/push 1/imm32/block-depth
17496     51/push-ecx
17497     68/push 0x11/imm32/alloc-id:fake
17498     68/push 0/imm32/name
17499     68/push 0/imm32/name
17500     68/push 0x11/imm32/alloc-id:fake:payload
17501     89/<- %ecx 4/r32/esp
17502 $test-add-literal-to-eax:initialize-var-name:
17503     # v->name = "v"
17504     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17505     (copy-array Heap "v" %eax)
17506 $test-add-literal-to-eax:initialize-var-register:
17507     # v->register = "eax"
17508     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17509     (copy-array Heap "eax" %eax)
17510 $test-add-literal-to-eax:initialize-literal-type:
17511     # var type/edx: (payload tree type-id) = literal
17512     68/push 0/imm32/right:null
17513     68/push 0/imm32/right:null
17514     68/push 0/imm32/left:unused
17515     68/push 0/imm32/value:literal
17516     68/push 1/imm32/is-atom?:true
17517     68/push 0x11/imm32/alloc-id:fake:payload
17518     89/<- %edx 4/r32/esp
17519 $test-add-literal-to-eax:initialize-literal:
17520     # var l/edx: (payload var)
17521     68/push 0/imm32/register
17522     68/push 0/imm32/register
17523     68/push 0/imm32/no-stack-offset
17524     68/push 1/imm32/block-depth
17525     52/push-edx
17526     68/push 0x11/imm32/alloc-id:fake
17527     68/push 0/imm32/name
17528     68/push 0/imm32/name
17529     68/push 0x11/imm32/alloc-id:fake:payload
17530     89/<- %edx 4/r32/esp
17531 $test-add-literal-to-eax:initialize-literal-value:
17532     # l->name = "0x34"
17533     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17534     (copy-array Heap "0x34" %eax)
17535 $test-add-literal-to-eax:initialize-inouts:
17536     # var inouts/esi: (payload stmt-var) = [l]
17537     68/push 0/imm32/is-deref:false
17538     68/push 0/imm32/next
17539     68/push 0/imm32/next
17540     52/push-edx/l
17541     68/push 0x11/imm32/alloc-id:fake
17542     68/push 0x11/imm32/alloc-id:fake:payload
17543     89/<- %esi 4/r32/esp
17544 $test-add-literal-to-eax:initialize-outputs:
17545     # var outputs/edi: (payload stmt-var) = [v]
17546     68/push 0/imm32/is-deref:false
17547     68/push 0/imm32/next
17548     68/push 0/imm32/next
17549     51/push-ecx/v
17550     68/push 0x11/imm32/alloc-id:fake
17551     68/push 0x11/imm32/alloc-id:fake:payload
17552     89/<- %edi 4/r32/esp
17553 $test-add-literal-to-eax:initialize-stmt:
17554     # var stmt/esi: (addr statement)
17555     68/push 0/imm32/next
17556     68/push 0/imm32/next
17557     57/push-edi/outputs
17558     68/push 0x11/imm32/alloc-id:fake
17559     56/push-esi/inouts
17560     68/push 0x11/imm32/alloc-id:fake
17561     68/push 0/imm32/operation
17562     68/push 0/imm32/operation
17563     68/push 1/imm32/tag:stmt1
17564     89/<- %esi 4/r32/esp
17565 $test-add-literal-to-eax:initialize-stmt-operation:
17566     # stmt->operation = "add"
17567     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17568     (copy-array Heap "add" %eax)
17569     # convert
17570     c7 0/subop/copy *Curr-block-depth 0/imm32
17571     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17572     (flush _test-output-buffered-file)
17573 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17579     # check output
17580     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
17581     # . epilogue
17582     89/<- %esp 5/r32/ebp
17583     5d/pop-to-ebp
17584     c3/return
17585 
17586 test-add-literal-to-reg:
17587     #   var1/ecx <- add 0x34
17588     # =>
17589     #   81 0/subop/add %ecx 0x34/imm32
17590     #
17591     # . prologue
17592     55/push-ebp
17593     89/<- %ebp 4/r32/esp
17594     # setup
17595     (clear-stream _test-output-stream)
17596     (clear-stream $_test-output-buffered-file->buffer)
17597 $test-add-literal-to-reg:initialize-var-type:
17598     # var type/ecx: (payload tree type-id) = int
17599     68/push 0/imm32/right:null
17600     68/push 0/imm32/right:null
17601     68/push 0/imm32/left:unused
17602     68/push 1/imm32/value:int
17603     68/push 1/imm32/is-atom?:true
17604     68/push 0x11/imm32/alloc-id:fake:payload
17605     89/<- %ecx 4/r32/esp
17606 $test-add-literal-to-reg:initialize-var:
17607     # var v/ecx: (payload var)
17608     68/push 0/imm32/register
17609     68/push 0/imm32/register
17610     68/push 0/imm32/no-stack-offset
17611     68/push 1/imm32/block-depth
17612     51/push-ecx
17613     68/push 0x11/imm32/alloc-id:fake
17614     68/push 0/imm32/name
17615     68/push 0/imm32/name
17616     68/push 0x11/imm32/alloc-id:fake:payload
17617     89/<- %ecx 4/r32/esp
17618 $test-add-literal-to-reg:initialize-var-name:
17619     # v->name = "v"
17620     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17621     (copy-array Heap "v" %eax)
17622 $test-add-literal-to-reg:initialize-var-register:
17623     # v->register = "ecx"
17624     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17625     (copy-array Heap "ecx" %eax)
17626 $test-add-literal-to-reg:initialize-literal-type:
17627     # var type/edx: (payload tree type-id) = literal
17628     68/push 0/imm32/right:null
17629     68/push 0/imm32/right:null
17630     68/push 0/imm32/left:unused
17631     68/push 0/imm32/value:literal
17632     68/push 1/imm32/is-atom?:true
17633     68/push 0x11/imm32/alloc-id:fake:payload
17634     89/<- %edx 4/r32/esp
17635 $test-add-literal-to-reg:initialize-literal:
17636     # var l/edx: (payload var)
17637     68/push 0/imm32/register
17638     68/push 0/imm32/register
17639     68/push 0/imm32/no-stack-offset
17640     68/push 1/imm32/block-depth
17641     52/push-edx
17642     68/push 0x11/imm32/alloc-id:fake
17643     68/push 0/imm32/name
17644     68/push 0/imm32/name
17645     68/push 0x11/imm32/alloc-id:fake:payload
17646     89/<- %edx 4/r32/esp
17647 $test-add-literal-to-reg:initialize-literal-value:
17648     # l->name = "0x34"
17649     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17650     (copy-array Heap "0x34" %eax)
17651 $test-add-literal-to-reg:initialize-inouts:
17652     # var inouts/esi: (payload stmt-var) = [l]
17653     68/push 0/imm32/is-deref:false
17654     68/push 0/imm32/next
17655     68/push 0/imm32/next
17656     52/push-edx/l
17657     68/push 0x11/imm32/alloc-id:fake
17658     68/push 0x11/imm32/alloc-id:fake:payload
17659     89/<- %esi 4/r32/esp
17660 $test-add-literal-to-reg:initialize-outputs:
17661     # var outputs/edi: (payload stmt-var) = [v]
17662     68/push 0/imm32/is-deref:false
17663     68/push 0/imm32/next
17664     68/push 0/imm32/next
17665     51/push-ecx/v
17666     68/push 0x11/imm32/alloc-id:fake
17667     68/push 0x11/imm32/alloc-id:fake:payload
17668     89/<- %edi 4/r32/esp
17669 $test-add-literal-to-reg:initialize-stmt:
17670     # var stmt/esi: (addr statement)
17671     68/push 0/imm32/next
17672     68/push 0/imm32/next
17673     57/push-edi/outputs
17674     68/push 0x11/imm32/alloc-id:fake
17675     56/push-esi/inouts
17676     68/push 0x11/imm32/alloc-id:fake
17677     68/push 0/imm32/operation
17678     68/push 0/imm32/operation
17679     68/push 1/imm32/tag:stmt1
17680     89/<- %esi 4/r32/esp
17681 $test-add-literal-to-reg:initialize-stmt-operation:
17682     # stmt->operation = "add"
17683     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17684     (copy-array Heap "add" %eax)
17685     # convert
17686     c7 0/subop/copy *Curr-block-depth 0/imm32
17687     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17688     (flush _test-output-buffered-file)
17689 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17695     # check output
17696     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
17697     # . epilogue
17698     89/<- %esp 5/r32/ebp
17699     5d/pop-to-ebp
17700     c3/return
17701 
17702 test-add-literal-to-mem:
17703     #   add-to var1, 0x34
17704     # =>
17705     #   81 0/subop/add %eax 0x34/imm32
17706     #
17707     # . prologue
17708     55/push-ebp
17709     89/<- %ebp 4/r32/esp
17710     # setup
17711     (clear-stream _test-output-stream)
17712     (clear-stream $_test-output-buffered-file->buffer)
17713 $test-add-literal-to-mem:initialize-type:
17714     # var type/ecx: (payload tree type-id) = int
17715     68/push 0/imm32/right:null
17716     68/push 0/imm32/right:null
17717     68/push 0/imm32/left:unused
17718     68/push 1/imm32/value:int
17719     68/push 1/imm32/is-atom?:true
17720     68/push 0x11/imm32/alloc-id:fake:payload
17721     89/<- %ecx 4/r32/esp
17722 $test-add-literal-to-mem:initialize-var1:
17723     # var var1/ecx: (payload var)
17724     68/push 0/imm32/register
17725     68/push 0/imm32/register
17726     68/push 8/imm32/stack-offset
17727     68/push 1/imm32/block-depth
17728     51/push-ecx
17729     68/push 0x11/imm32/alloc-id:fake
17730     68/push 0/imm32/name
17731     68/push 0/imm32/name
17732     68/push 0x11/imm32/alloc-id:fake:payload
17733     89/<- %ecx 4/r32/esp
17734 $test-add-literal-to-mem:initialize-var1-name:
17735     # var1->name = "var1"
17736     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17737     (copy-array Heap "var1" %eax)
17738 $test-add-literal-to-mem:initialize-literal-type:
17739     # var type/edx: (payload tree type-id) = literal
17740     68/push 0/imm32/right:null
17741     68/push 0/imm32/right:null
17742     68/push 0/imm32/left:unused
17743     68/push 0/imm32/value:literal
17744     68/push 1/imm32/is-atom?:true
17745     68/push 0x11/imm32/alloc-id:fake:payload
17746     89/<- %edx 4/r32/esp
17747 $test-add-literal-to-mem:initialize-literal:
17748     # var l/edx: (payload var)
17749     68/push 0/imm32/register
17750     68/push 0/imm32/register
17751     68/push 0/imm32/no-stack-offset
17752     68/push 1/imm32/block-depth
17753     52/push-edx
17754     68/push 0x11/imm32/alloc-id:fake
17755     68/push 0/imm32/name
17756     68/push 0/imm32/name
17757     68/push 0x11/imm32/alloc-id:fake:payload
17758     89/<- %edx 4/r32/esp
17759 $test-add-literal-to-mem:initialize-literal-value:
17760     # l->name = "0x34"
17761     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17762     (copy-array Heap "0x34" %eax)
17763 $test-add-literal-to-mem:initialize-inouts:
17764     # var inouts/esi: (payload stmt-var) = [l]
17765     68/push 0/imm32/is-deref:false
17766     68/push 0/imm32/next
17767     68/push 0/imm32/next
17768     52/push-edx/l
17769     68/push 0x11/imm32/alloc-id:fake
17770     68/push 0x11/imm32/alloc-id:fake:payload
17771     89/<- %esi 4/r32/esp
17772     # var inouts = (handle stmt-var) = [var1, var2]
17773     68/push 0/imm32/is-deref:false
17774     56/push-esi/next
17775     68/push 0x11/imm32/alloc-id:fake
17776     51/push-ecx/var1
17777     68/push 0x11/imm32/alloc-id:fake
17778     68/push 0x11/imm32/alloc-id:fake:payload
17779     89/<- %esi 4/r32/esp
17780 $test-add-literal-to-mem:initialize-stmt:
17781     # var stmt/esi: (addr statement)
17782     68/push 0/imm32/next
17783     68/push 0/imm32/next
17784     68/push 0/imm32/outputs
17785     68/push 0/imm32/outputs
17786     56/push-esi/inouts
17787     68/push 0x11/imm32/alloc-id:fake
17788     68/push 0/imm32/operation
17789     68/push 0/imm32/operation
17790     68/push 1/imm32/tag:stmt1
17791     89/<- %esi 4/r32/esp
17792 $test-add-literal-to-mem:initialize-stmt-operation:
17793     # stmt->operation = "add-to"
17794     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17795     (copy-array Heap "add-to" %eax)
17796     # convert
17797     c7 0/subop/copy *Curr-block-depth 0/imm32
17798     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17799     (flush _test-output-buffered-file)
17800 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17806     # check output
17807     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
17808     # . epilogue
17809     89/<- %esp 5/r32/ebp
17810     5d/pop-to-ebp
17811     c3/return
17812 
17813 test-compare-reg-with-reg:
17814     #   compare var1/ecx, var2/eax
17815     # =>
17816     #   39/compare %ecx 0/r32/eax
17817     #
17818     # . prologue
17819     55/push-ebp
17820     89/<- %ebp 4/r32/esp
17821     # setup
17822     (clear-stream _test-output-stream)
17823     (clear-stream $_test-output-buffered-file->buffer)
17824 $test-compare-reg-with-reg:initialize-type:
17825     # var type/ecx: (payload tree type-id) = int
17826     68/push 0/imm32/right:null
17827     68/push 0/imm32/right:null
17828     68/push 0/imm32/left:unused
17829     68/push 1/imm32/value:int
17830     68/push 1/imm32/is-atom?:true
17831     68/push 0x11/imm32/alloc-id:fake:payload
17832     89/<- %ecx 4/r32/esp
17833 $test-compare-reg-with-reg:initialize-var1:
17834     # var var1/ecx: (payload var)
17835     68/push 0/imm32/register
17836     68/push 0/imm32/register
17837     68/push 0/imm32/no-stack-offset
17838     68/push 1/imm32/block-depth
17839     51/push-ecx
17840     68/push 0x11/imm32/alloc-id:fake
17841     68/push 0/imm32/name
17842     68/push 0/imm32/name
17843     68/push 0x11/imm32/alloc-id:fake:payload
17844     89/<- %ecx 4/r32/esp
17845 $test-compare-reg-with-reg:initialize-var1-name:
17846     # var1->name = "var1"
17847     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17848     (copy-array Heap "var1" %eax)
17849 $test-compare-reg-with-reg:initialize-var1-register:
17850     # var1->register = "ecx"
17851     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17852     (copy-array Heap "ecx" %eax)
17853 $test-compare-reg-with-reg:initialize-var2:
17854     # var var2/edx: (payload var)
17855     68/push 0/imm32/register
17856     68/push 0/imm32/register
17857     68/push 0/imm32/no-stack-offset
17858     68/push 1/imm32/block-depth
17859     ff 6/subop/push *(ecx+0x10)
17860     68/push 0x11/imm32/alloc-id:fake
17861     68/push 0/imm32/name
17862     68/push 0/imm32/name
17863     68/push 0x11/imm32/alloc-id:fake:payload
17864     89/<- %edx 4/r32/esp
17865 $test-compare-reg-with-reg:initialize-var2-name:
17866     # var2->name = "var2"
17867     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17868     (copy-array Heap "var2" %eax)
17869 $test-compare-reg-with-reg:initialize-var2-register:
17870     # var2->register = "eax"
17871     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17872     (copy-array Heap "eax" %eax)
17873 $test-compare-reg-with-reg:initialize-inouts:
17874     # var inouts/esi: (payload stmt-var) = [var2]
17875     68/push 0/imm32/is-deref:false
17876     68/push 0/imm32/next
17877     68/push 0/imm32/next
17878     52/push-edx/var2
17879     68/push 0x11/imm32/alloc-id:fake
17880     68/push 0x11/imm32/alloc-id:fake:payload
17881     89/<- %esi 4/r32/esp
17882     # inouts = [var1, var2]
17883     68/push 0/imm32/is-deref:false
17884     56/push-esi/next
17885     68/push 0x11/imm32/alloc-id:fake
17886     51/push-ecx/var1
17887     68/push 0x11/imm32/alloc-id:fake
17888     68/push 0x11/imm32/alloc-id:fake:payload
17889     89/<- %esi 4/r32/esp
17890 $test-compare-reg-with-reg:initialize-stmt:
17891     # var stmt/esi: (addr statement)
17892     68/push 0/imm32/next
17893     68/push 0/imm32/next
17894     68/push 0/imm32/outputs
17895     68/push 0/imm32/outputs
17896     56/push-esi/inouts
17897     68/push 0x11/imm32/alloc-id:fake
17898     68/push 0/imm32/operation
17899     68/push 0/imm32/operation
17900     68/push 1/imm32/tag:stmt1
17901     89/<- %esi 4/r32/esp
17902 $test-compare-reg-with-reg:initialize-stmt-operation:
17903     # stmt->operation = "compare"
17904     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17905     (copy-array Heap "compare" %eax)
17906     # convert
17907     c7 0/subop/copy *Curr-block-depth 0/imm32
17908     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17909     (flush _test-output-buffered-file)
17910 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17916     # check output
17917     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
17918     # . epilogue
17919     89/<- %esp 5/r32/ebp
17920     5d/pop-to-ebp
17921     c3/return
17922 
17923 test-compare-mem-with-reg:
17924     #   compare var1, var2/eax
17925     # =>
17926     #   39/compare *(ebp+___) 0/r32/eax
17927     #
17928     # . prologue
17929     55/push-ebp
17930     89/<- %ebp 4/r32/esp
17931     # setup
17932     (clear-stream _test-output-stream)
17933     (clear-stream $_test-output-buffered-file->buffer)
17934 $test-compare-mem-with-reg:initialize-type:
17935     # var type/ecx: (payload tree type-id) = int
17936     68/push 0/imm32/right:null
17937     68/push 0/imm32/right:null
17938     68/push 0/imm32/left:unused
17939     68/push 1/imm32/value:int
17940     68/push 1/imm32/is-atom?:true
17941     68/push 0x11/imm32/alloc-id:fake:payload
17942     89/<- %ecx 4/r32/esp
17943 $test-compare-mem-with-reg:initialize-var1:
17944     # var var1/ecx: (payload var)
17945     68/push 0/imm32/register
17946     68/push 0/imm32/register
17947     68/push 8/imm32/stack-offset
17948     68/push 1/imm32/block-depth
17949     51/push-ecx
17950     68/push 0x11/imm32/alloc-id:fake
17951     68/push 0/imm32/name
17952     68/push 0/imm32/name
17953     68/push 0x11/imm32/alloc-id:fake:payload
17954     89/<- %ecx 4/r32/esp
17955 $test-compare-mem-with-reg:initialize-var1-name:
17956     # var1->name = "var1"
17957     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17958     (copy-array Heap "var1" %eax)
17959 $test-compare-mem-with-reg:initialize-var2:
17960     # var var2/edx: (payload var)
17961     68/push 0/imm32/register
17962     68/push 0/imm32/register
17963     68/push 0/imm32/no-stack-offset
17964     68/push 1/imm32/block-depth
17965     ff 6/subop/push *(ecx+0x10)
17966     68/push 0x11/imm32/alloc-id:fake
17967     68/push 0/imm32/name
17968     68/push 0/imm32/name
17969     68/push 0x11/imm32/alloc-id:fake:payload
17970     89/<- %edx 4/r32/esp
17971 $test-compare-mem-with-reg:initialize-var2-name:
17972     # var2->name = "var2"
17973     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17974     (copy-array Heap "var2" %eax)
17975 $test-compare-mem-with-reg:initialize-var2-register:
17976     # var2->register = "eax"
17977     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17978     (copy-array Heap "eax" %eax)
17979 $test-compare-mem-with-reg:initialize-inouts:
17980     # var inouts/esi: (payload stmt-var) = [var2]
17981     68/push 0/imm32/is-deref:false
17982     68/push 0/imm32/next
17983     68/push 0/imm32/next
17984     52/push-edx/var2
17985     68/push 0x11/imm32/alloc-id:fake
17986     68/push 0x11/imm32/alloc-id:fake:payload
17987     89/<- %esi 4/r32/esp
17988     # inouts = [var1, var2]
17989     68/push 0/imm32/is-deref:false
17990     56/push-esi/next
17991     68/push 0x11/imm32/alloc-id:fake
17992     51/push-ecx/var1
17993     68/push 0x11/imm32/alloc-id:fake
17994     68/push 0x11/imm32/alloc-id:fake:payload
17995     89/<- %esi 4/r32/esp
17996 $test-compare-mem-with-reg:initialize-stmt:
17997     # var stmt/esi: (addr statement)
17998     68/push 0/imm32/next
17999     68/push 0/imm32/next
18000     68/push 0/imm32/outputs
18001     68/push 0/imm32/outputs
18002     56/push-esi/inouts
18003     68/push 0x11/imm32/alloc-id:fake
18004     68/push 0/imm32/operation
18005     68/push 0/imm32/operation
18006     68/push 1/imm32/tag:stmt1
18007     89/<- %esi 4/r32/esp
18008 $test-compare-mem-with-reg:initialize-stmt-operation:
18009     # stmt->operation = "compare"
18010     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18011     (copy-array Heap "compare" %eax)
18012     # convert
18013     c7 0/subop/copy *Curr-block-depth 0/imm32
18014     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18015     (flush _test-output-buffered-file)
18016 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18022     # check output
18023     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
18024     # . epilogue
18025     89/<- %esp 5/r32/ebp
18026     5d/pop-to-ebp
18027     c3/return
18028 
18029 test-compare-reg-with-mem:
18030     #   compare var1/eax, var2
18031     # =>
18032     #   3b/compare<- *(ebp+___) 0/r32/eax
18033     #
18034     # . prologue
18035     55/push-ebp
18036     89/<- %ebp 4/r32/esp
18037     # setup
18038     (clear-stream _test-output-stream)
18039     (clear-stream $_test-output-buffered-file->buffer)
18040 $test-compare-reg-with-mem:initialize-type:
18041     # var type/ecx: (payload tree type-id) = int
18042     68/push 0/imm32/right:null
18043     68/push 0/imm32/right:null
18044     68/push 0/imm32/left:unused
18045     68/push 1/imm32/value:int
18046     68/push 1/imm32/is-atom?:true
18047     68/push 0x11/imm32/alloc-id:fake:payload
18048     89/<- %ecx 4/r32/esp
18049 $test-compare-reg-with-mem:initialize-var1:
18050     # var var1/ecx: (payload var)
18051     68/push 0/imm32/register
18052     68/push 0/imm32/register
18053     68/push 0/imm32/no-stack-offset
18054     68/push 1/imm32/block-depth
18055     51/push-ecx
18056     68/push 0x11/imm32/alloc-id:fake
18057     68/push 0/imm32/name
18058     68/push 0/imm32/name
18059     68/push 0x11/imm32/alloc-id:fake:payload
18060     89/<- %ecx 4/r32/esp
18061 $test-compare-reg-with-mem:initialize-var1-name:
18062     # var1->name = "var1"
18063     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18064     (copy-array Heap "var1" %eax)
18065 $test-compare-reg-with-mem:initialize-var1-register:
18066     # var1->register = "eax"
18067     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18068     (copy-array Heap "eax" %eax)
18069 $test-compare-reg-with-mem:initialize-var2:
18070     # var var2/edx: (payload var)
18071     68/push 0/imm32/register
18072     68/push 0/imm32/register
18073     68/push 8/imm32/stack-offset
18074     68/push 1/imm32/block-depth
18075     ff 6/subop/push *(ecx+0x10)
18076     68/push 0x11/imm32/alloc-id:fake
18077     68/push 0/imm32/name
18078     68/push 0/imm32/name
18079     68/push 0x11/imm32/alloc-id:fake:payload
18080     89/<- %edx 4/r32/esp
18081 $test-compare-reg-with-mem:initialize-var2-name:
18082     # var2->name = "var2"
18083     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18084     (copy-array Heap "var2" %eax)
18085 $test-compare-reg-with-mem:initialize-inouts:
18086     # var inouts/esi: (payload stmt-var) = [var2]
18087     68/push 0/imm32/is-deref:false
18088     68/push 0/imm32/next
18089     68/push 0/imm32/next
18090     52/push-edx/var2
18091     68/push 0x11/imm32/alloc-id:fake
18092     68/push 0x11/imm32/alloc-id:fake:payload
18093     89/<- %esi 4/r32/esp
18094     # inouts = [var1, var2]
18095     68/push 0/imm32/is-deref:false
18096     56/push-esi/next
18097     68/push 0x11/imm32/alloc-id:fake
18098     51/push-ecx/var1
18099     68/push 0x11/imm32/alloc-id:fake
18100     68/push 0x11/imm32/alloc-id:fake:payload
18101     89/<- %esi 4/r32/esp
18102 $test-compare-reg-with-mem:initialize-stmt:
18103     # var stmt/esi: (addr statement)
18104     68/push 0/imm32/next
18105     68/push 0/imm32/next
18106     68/push 0/imm32/outputs
18107     68/push 0/imm32/outputs
18108     56/push-esi/inouts
18109     68/push 0x11/imm32/alloc-id:fake
18110     68/push 0/imm32/operation
18111     68/push 0/imm32/operation
18112     68/push 1/imm32/tag:stmt1
18113     89/<- %esi 4/r32/esp
18114 $test-compare-reg-with-mem:initialize-stmt-operation:
18115     # stmt->operation = "compare"
18116     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18117     (copy-array Heap "compare" %eax)
18118     # convert
18119     c7 0/subop/copy *Curr-block-depth 0/imm32
18120     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18121     (flush _test-output-buffered-file)
18122 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18128     # check output
18129     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
18130     # . epilogue
18131     89/<- %esp 5/r32/ebp
18132     5d/pop-to-ebp
18133     c3/return
18134 
18135 test-compare-mem-with-literal:
18136     #   compare var1, 0x34
18137     # =>
18138     #   81 7/subop/compare *(ebp+___) 0x34/imm32
18139     #
18140     # . prologue
18141     55/push-ebp
18142     89/<- %ebp 4/r32/esp
18143     # setup
18144     (clear-stream _test-output-stream)
18145     (clear-stream $_test-output-buffered-file->buffer)
18146 $test-compare-mem-with-literal:initialize-type:
18147     # var type/ecx: (payload tree type-id) = int
18148     68/push 0/imm32/right:null
18149     68/push 0/imm32/right:null
18150     68/push 0/imm32/left:unused
18151     68/push 1/imm32/value:int
18152     68/push 1/imm32/is-atom?:true
18153     68/push 0x11/imm32/alloc-id:fake:payload
18154     89/<- %ecx 4/r32/esp
18155 $test-compare-mem-with-literal:initialize-var1:
18156     # var var1/ecx: (payload var)
18157     68/push 0/imm32/register
18158     68/push 0/imm32/register
18159     68/push 8/imm32/stack-offset
18160     68/push 1/imm32/block-depth
18161     51/push-ecx
18162     68/push 0x11/imm32/alloc-id:fake
18163     68/push 0/imm32/name
18164     68/push 0/imm32/name
18165     68/push 0x11/imm32/alloc-id:fake:payload
18166     89/<- %ecx 4/r32/esp
18167 $test-compare-mem-with-literal:initialize-var1-name:
18168     # var1->name = "var1"
18169     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18170     (copy-array Heap "var1" %eax)
18171 $test-compare-mem-with-literal:initialize-literal-type:
18172     # var type/edx: (payload tree type-id) = literal
18173     68/push 0/imm32/right:null
18174     68/push 0/imm32/right:null
18175     68/push 0/imm32/left:unused
18176     68/push 0/imm32/value:literal
18177     68/push 1/imm32/is-atom?:true
18178     68/push 0x11/imm32/alloc-id:fake:payload
18179     89/<- %edx 4/r32/esp
18180 $test-compare-mem-with-literal:initialize-literal:
18181     # var l/edx: (payload var)
18182     68/push 0/imm32/register
18183     68/push 0/imm32/register
18184     68/push 0/imm32/no-stack-offset
18185     68/push 1/imm32/block-depth
18186     52/push-edx
18187     68/push 0x11/imm32/alloc-id:fake
18188     68/push 0/imm32/name
18189     68/push 0/imm32/name
18190     68/push 0x11/imm32/alloc-id:fake:payload
18191     89/<- %edx 4/r32/esp
18192 $test-compare-mem-with-literal:initialize-literal-value:
18193     # l->name = "0x34"
18194     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18195     (copy-array Heap "0x34" %eax)
18196 $test-compare-mem-with-literal:initialize-inouts:
18197     # var inouts/esi: (payload stmt-var) = [l]
18198     68/push 0/imm32/is-deref:false
18199     68/push 0/imm32/next
18200     68/push 0/imm32/next
18201     52/push-edx/l
18202     68/push 0x11/imm32/alloc-id:fake
18203     68/push 0x11/imm32/alloc-id:fake:payload
18204     89/<- %esi 4/r32/esp
18205     # var inouts = (handle stmt-var) = [var1, var2]
18206     68/push 0/imm32/is-deref:false
18207     56/push-esi/next
18208     68/push 0x11/imm32/alloc-id:fake
18209     51/push-ecx/var1
18210     68/push 0x11/imm32/alloc-id:fake
18211     68/push 0x11/imm32/alloc-id:fake:payload
18212     89/<- %esi 4/r32/esp
18213 $test-compare-mem-with-literal:initialize-stmt:
18214     # var stmt/esi: (addr statement)
18215     68/push 0/imm32/next
18216     68/push 0/imm32/next
18217     68/push 0/imm32/outputs
18218     68/push 0/imm32/outputs
18219     56/push-esi/inouts
18220     68/push 0x11/imm32/alloc-id:fake
18221     68/push 0/imm32/operation
18222     68/push 0/imm32/operation
18223     68/push 1/imm32/tag:stmt1
18224     89/<- %esi 4/r32/esp
18225 $test-compare-mem-with-literal:initialize-stmt-operation:
18226     # stmt->operation = "compare"
18227     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18228     (copy-array Heap "compare" %eax)
18229     # convert
18230     c7 0/subop/copy *Curr-block-depth 0/imm32
18231     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18232     (flush _test-output-buffered-file)
18233 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18239     # check output
18240     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
18241     # . epilogue
18242     89/<- %esp 5/r32/ebp
18243     5d/pop-to-ebp
18244     c3/return
18245 
18246 test-compare-eax-with-literal:
18247     #   compare var1/eax 0x34
18248     # =>
18249     #   3d/compare-eax-with 0x34/imm32
18250     #
18251     # . prologue
18252     55/push-ebp
18253     89/<- %ebp 4/r32/esp
18254     # setup
18255     (clear-stream _test-output-stream)
18256     (clear-stream $_test-output-buffered-file->buffer)
18257 $test-compare-eax-with-literal:initialize-type:
18258     # var type/ecx: (payload tree type-id) = int
18259     68/push 0/imm32/right:null
18260     68/push 0/imm32/right:null
18261     68/push 0/imm32/left:unused
18262     68/push 1/imm32/value:int
18263     68/push 1/imm32/is-atom?:true
18264     68/push 0x11/imm32/alloc-id:fake:payload
18265     89/<- %ecx 4/r32/esp
18266 $test-compare-eax-with-literal:initialize-var1:
18267     # var var1/ecx: (payload var)
18268     68/push 0/imm32/register
18269     68/push 0/imm32/register
18270     68/push 0/imm32/no-stack-offset
18271     68/push 1/imm32/block-depth
18272     51/push-ecx
18273     68/push 0x11/imm32/alloc-id:fake
18274     68/push 0/imm32/name
18275     68/push 0/imm32/name
18276     68/push 0x11/imm32/alloc-id:fake:payload
18277     89/<- %ecx 4/r32/esp
18278 $test-compare-eax-with-literal:initialize-var1-name:
18279     # var1->name = "var1"
18280     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18281     (copy-array Heap "var1" %eax)
18282 $test-compare-eax-with-literal:initialize-var1-register:
18283     # v->register = "eax"
18284     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18285     (copy-array Heap "eax" %eax)
18286 $test-compare-eax-with-literal:initialize-literal-type:
18287     # var type/edx: (payload tree type-id) = literal
18288     68/push 0/imm32/right:null
18289     68/push 0/imm32/right:null
18290     68/push 0/imm32/left:unused
18291     68/push 0/imm32/value:literal
18292     68/push 1/imm32/is-atom?:true
18293     68/push 0x11/imm32/alloc-id:fake:payload
18294     89/<- %edx 4/r32/esp
18295 $test-compare-eax-with-literal:initialize-literal:
18296     # var l/edx: (payload var)
18297     68/push 0/imm32/register
18298     68/push 0/imm32/register
18299     68/push 0/imm32/no-stack-offset
18300     68/push 1/imm32/block-depth
18301     52/push-edx
18302     68/push 0x11/imm32/alloc-id:fake
18303     68/push 0/imm32/name
18304     68/push 0/imm32/name
18305     68/push 0x11/imm32/alloc-id:fake:payload
18306     89/<- %edx 4/r32/esp
18307 $test-compare-eax-with-literal:initialize-literal-value:
18308     # l->name = "0x34"
18309     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18310     (copy-array Heap "0x34" %eax)
18311 $test-compare-eax-with-literal:initialize-inouts:
18312     # var inouts/esi: (payload stmt-var) = [l]
18313     68/push 0/imm32/is-deref:false
18314     68/push 0/imm32/next
18315     68/push 0/imm32/next
18316     52/push-edx/l
18317     68/push 0x11/imm32/alloc-id:fake
18318     68/push 0x11/imm32/alloc-id:fake:payload
18319     89/<- %esi 4/r32/esp
18320     # var inouts = (handle stmt-var) = [var1, var2]
18321     68/push 0/imm32/is-deref:false
18322     56/push-esi/next
18323     68/push 0x11/imm32/alloc-id:fake
18324     51/push-ecx/var1
18325     68/push 0x11/imm32/alloc-id:fake
18326     68/push 0x11/imm32/alloc-id:fake:payload
18327     89/<- %esi 4/r32/esp
18328 $test-compare-eax-with-literal:initialize-stmt:
18329     # var stmt/esi: (addr statement)
18330     68/push 0/imm32/next
18331     68/push 0/imm32/next
18332     68/push 0/imm32/outputs
18333     68/push 0/imm32/outputs
18334     56/push-esi/inouts
18335     68/push 0x11/imm32/alloc-id:fake
18336     68/push 0/imm32/operation
18337     68/push 0/imm32/operation
18338     68/push 1/imm32/tag:stmt1
18339     89/<- %esi 4/r32/esp
18340 $test-compare-eax-with-literal:initialize-stmt-operation:
18341     # stmt->operation = "compare"
18342     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18343     (copy-array Heap "compare" %eax)
18344     # convert
18345     c7 0/subop/copy *Curr-block-depth 0/imm32
18346     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18347     (flush _test-output-buffered-file)
18348 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18354     # check output
18355     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
18356     # . epilogue
18357     89/<- %esp 5/r32/ebp
18358     5d/pop-to-ebp
18359     c3/return
18360 
18361 test-compare-reg-with-literal:
18362     #   compare var1/ecx 0x34
18363     # =>
18364     #   81 7/subop/compare %ecx 0x34/imm32
18365     #
18366     # . prologue
18367     55/push-ebp
18368     89/<- %ebp 4/r32/esp
18369     # setup
18370     (clear-stream _test-output-stream)
18371     (clear-stream $_test-output-buffered-file->buffer)
18372 $test-compare-reg-with-literal:initialize-type:
18373     # var type/ecx: (payload tree type-id) = int
18374     68/push 0/imm32/right:null
18375     68/push 0/imm32/right:null
18376     68/push 0/imm32/left:unused
18377     68/push 1/imm32/value:int
18378     68/push 1/imm32/is-atom?:true
18379     68/push 0x11/imm32/alloc-id:fake:payload
18380     89/<- %ecx 4/r32/esp
18381 $test-compare-reg-with-literal:initialize-var1:
18382     # var var1/ecx: (payload var)
18383     68/push 0/imm32/register
18384     68/push 0/imm32/register
18385     68/push 0/imm32/no-stack-offset
18386     68/push 1/imm32/block-depth
18387     51/push-ecx
18388     68/push 0x11/imm32/alloc-id:fake
18389     68/push 0/imm32/name
18390     68/push 0/imm32/name
18391     68/push 0x11/imm32/alloc-id:fake:payload
18392     89/<- %ecx 4/r32/esp
18393 $test-compare-reg-with-literal:initialize-var1-name:
18394     # var1->name = "var1"
18395     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18396     (copy-array Heap "var1" %eax)
18397 $test-compare-reg-with-literal:initialize-var1-register:
18398     # v->register = "ecx"
18399     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18400     (copy-array Heap "ecx" %eax)
18401 $test-compare-reg-with-literal:initialize-literal-type:
18402     # var type/edx: (payload tree type-id) = literal
18403     68/push 0/imm32/right:null
18404     68/push 0/imm32/right:null
18405     68/push 0/imm32/left:unused
18406     68/push 0/imm32/value:literal
18407     68/push 1/imm32/is-atom?:true
18408     68/push 0x11/imm32/alloc-id:fake:payload
18409     89/<- %edx 4/r32/esp
18410 $test-compare-reg-with-literal:initialize-literal:
18411     # var l/edx: (payload var)
18412     68/push 0/imm32/register
18413     68/push 0/imm32/register
18414     68/push 0/imm32/no-stack-offset
18415     68/push 1/imm32/block-depth
18416     52/push-edx
18417     68/push 0x11/imm32/alloc-id:fake
18418     68/push 0/imm32/name
18419     68/push 0/imm32/name
18420     68/push 0x11/imm32/alloc-id:fake:payload
18421     89/<- %edx 4/r32/esp
18422 $test-compare-reg-with-literal:initialize-literal-value:
18423     # l->name = "0x34"
18424     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
18425     (copy-array Heap "0x34" %eax)
18426 $test-compare-reg-with-literal:initialize-inouts:
18427     # var inouts/esi: (payload stmt-var) = [l]
18428     68/push 0/imm32/is-deref:false
18429     68/push 0/imm32/next
18430     68/push 0/imm32/next
18431     52/push-edx/l
18432     68/push 0x11/imm32/alloc-id:fake
18433     68/push 0x11/imm32/alloc-id:fake:payload
18434     89/<- %esi 4/r32/esp
18435     # var inouts = (handle stmt-var) = [var1, var2]
18436     68/push 0/imm32/is-deref:false
18437     56/push-esi/next
18438     68/push 0x11/imm32/alloc-id:fake
18439     51/push-ecx/var1
18440     68/push 0x11/imm32/alloc-id:fake
18441     68/push 0x11/imm32/alloc-id:fake:payload
18442     89/<- %esi 4/r32/esp
18443 $test-compare-reg-with-literal:initialize-stmt:
18444     # var stmt/esi: (addr statement)
18445     68/push 0/imm32/next
18446     68/push 0/imm32/next
18447     68/push 0/imm32/outputs
18448     68/push 0/imm32/outputs
18449     56/push-esi/inouts
18450     68/push 0x11/imm32/alloc-id:fake
18451     68/push 0/imm32/operation
18452     68/push 0/imm32/operation
18453     68/push 1/imm32/tag:stmt1
18454     89/<- %esi 4/r32/esp
18455 $test-compare-reg-with-literal:initialize-stmt-operation:
18456     # stmt->operation = "compare"
18457     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18458     (copy-array Heap "compare" %eax)
18459     # convert
18460     c7 0/subop/copy *Curr-block-depth 0/imm32
18461     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18462     (flush _test-output-buffered-file)
18463 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18469     # check output
18470     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
18471     # . epilogue
18472     89/<- %esp 5/r32/ebp
18473     5d/pop-to-ebp
18474     c3/return
18475 
18476 test-emit-subx-stmt-function-call:
18477     # Call a function on a variable on the stack.
18478     #   f foo
18479     # =>
18480     #   (f *(ebp-8))
18481     # (Changing the function name supports overloading in general, but here it
18482     # just serves to help disambiguate things.)
18483     #
18484     # There's a variable on the var stack as follows:
18485     #   name: 'foo'
18486     #   type: int
18487     #   stack-offset: -8
18488     #
18489     # There's nothing in primitives.
18490     #
18491     # We don't perform any checking here on the type of 'f'.
18492     #
18493     # . prologue
18494     55/push-ebp
18495     89/<- %ebp 4/r32/esp
18496     # setup
18497     (clear-stream _test-output-stream)
18498     (clear-stream $_test-output-buffered-file->buffer)
18499 $test-emit-subx-function-call:initialize-type:
18500     # var type/ecx: (payload tree type-id) = int
18501     68/push 0/imm32/right:null
18502     68/push 0/imm32/right:null
18503     68/push 0/imm32/left:unused
18504     68/push 1/imm32/value:int
18505     68/push 1/imm32/is-atom?:true
18506     68/push 0x11/imm32/alloc-id:fake:payload
18507     89/<- %ecx 4/r32/esp
18508 $test-emit-subx-function-call:initialize-var:
18509     # var var-foo/ecx: (payload var) = var(type)
18510     68/push 0/imm32/no-register
18511     68/push 0/imm32/no-register
18512     68/push -8/imm32/stack-offset
18513     68/push 1/imm32/block-depth
18514     51/push-ecx/type
18515     68/push 0x11/imm32/alloc-id:fake
18516     68/push 0/imm32/name
18517     68/push 0/imm32/name
18518     68/push 0x11/imm32/alloc-id:fake:payload
18519     89/<- %ecx 4/r32/esp
18520 $test-emit-subx-function-call:initialize-var-name:
18521     # var-foo->name = "foo"
18522     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18523     (copy-array Heap "foo" %eax)
18524 $test-emit-subx-function-call:initialize-stmt-var:
18525     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
18526     68/push 0/imm32/is-deref:false
18527     68/push 0/imm32/next
18528     68/push 0/imm32/next
18529     51/push-ecx/var-foo
18530     68/push 0x11/imm32/alloc-id:fake
18531     68/push 0x11/imm32/alloc-id:fake:payload
18532     89/<- %ebx 4/r32/esp
18533 $test-emit-subx-function-call:initialize-stmt:
18534     # var stmt/esi: (addr statement)
18535     68/push 0/imm32/no-outputs
18536     68/push 0/imm32/no-outputs
18537     53/push-ebx/inouts
18538     68/push 0x11/imm32/alloc-id:fake
18539     68/push 0/imm32/operation
18540     68/push 0/imm32/operation
18541     68/push 1/imm32/tag
18542     89/<- %esi 4/r32/esp
18543 $test-emit-subx-function-call:initialize-stmt-operation:
18544     # stmt->operation = "f"
18545     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18546     (copy-array Heap "f" %eax)
18547     # convert
18548     c7 0/subop/copy *Curr-block-depth 0/imm32
18549     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
18550     (flush _test-output-buffered-file)
18551 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18557     # check output
18558     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
18559     # . epilogue
18560     89/<- %esp 5/r32/ebp
18561     5d/pop-to-ebp
18562     c3/return
18563 
18564 test-emit-subx-stmt-function-call-with-literal-arg:
18565     # Call a function on a literal.
18566     #   f 0x34
18567     # =>
18568     #   (f2 0x34)
18569     #
18570     # . prologue
18571     55/push-ebp
18572     89/<- %ebp 4/r32/esp
18573     # setup
18574     (clear-stream _test-output-stream)
18575     (clear-stream $_test-output-buffered-file->buffer)
18576 $test-emit-subx-function-call-with-literal-arg:initialize-type:
18577     # var type/ecx: (payload tree type-id) = int
18578     68/push 0/imm32/right:null
18579     68/push 0/imm32/right:null
18580     68/push 0/imm32/left:unused
18581     68/push 0/imm32/value:literal
18582     68/push 1/imm32/is-atom?:true
18583     68/push 0x11/imm32/alloc-id:fake:payload
18584     89/<- %ecx 4/r32/esp
18585 $test-emit-subx-function-call-with-literal-arg:initialize-var:
18586     # var var-foo/ecx: (payload var) = var(lit)
18587     68/push 0/imm32/no-register
18588     68/push 0/imm32/no-register
18589     68/push 0/imm32/no-stack-offset
18590     68/push 1/imm32/block-depth
18591     51/push-ecx/type
18592     68/push 0x11/imm32/alloc-id:fake
18593     68/push 0/imm32/name
18594     68/push 0/imm32/name
18595     68/push 0x11/imm32/alloc-id:fake:payload
18596     89/<- %ecx 4/r32/esp
18597 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
18598     # var-foo->name = "0x34"
18599     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18600     (copy-array Heap "0x34" %eax)
18601 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
18602     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
18603     68/push 0/imm32/is-deref:false
18604     68/push 0/imm32/next
18605     68/push 0/imm32/next
18606     51/push-ecx/var-foo
18607     68/push 0x11/imm32/alloc-id:fake
18608     68/push 0x11/imm32/alloc-id:fake:payload
18609     89/<- %ebx 4/r32/esp
18610 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
18611     # var stmt/esi: (addr statement)
18612     68/push 0/imm32/no-outputs
18613     68/push 0/imm32/no-outputs
18614     53/push-ebx/inouts
18615     68/push 0x11/imm32/alloc-id:fake
18616     68/push 0/imm32/operation
18617     68/push 0/imm32/operation
18618     68/push 1/imm32/tag
18619     89/<- %esi 4/r32/esp
18620 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
18621     # stmt->operation = "f"
18622     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18623     (copy-array Heap "f" %eax)
18624     # convert
18625     c7 0/subop/copy *Curr-block-depth 0/imm32
18626     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
18627     (flush _test-output-buffered-file)
18628 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18634     # check output
18635     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
18636     # . epilogue
18637     89/<- %esp 5/r32/ebp
18638     5d/pop-to-ebp
18639     c3/return
18640 
18641 emit-indent:  # out: (addr buffered-file), n: int
18642     # . prologue
18643     55/push-ebp
18644     89/<- %ebp 4/r32/esp
18645     # . save registers
18646     50/push-eax
18647     # var i/eax: int = n
18648     8b/-> *(ebp+0xc) 0/r32/eax
18649     {
18650       # if (i <= 0) break
18651       3d/compare-eax-with 0/imm32
18652       7e/jump-if-<= break/disp8
18653       (write-buffered *(ebp+8) "  ")
18654       48/decrement-eax
18655       eb/jump loop/disp8
18656     }
18657 $emit-indent:end:
18658     # . restore registers
18659     58/pop-to-eax
18660     # . epilogue
18661     89/<- %esp 5/r32/ebp
18662     5d/pop-to-ebp
18663     c3/return
18664 
18665 emit-subx-prologue:  # out: (addr buffered-file)
18666     # . prologue
18667     55/push-ebp
18668     89/<- %ebp 4/r32/esp
18669     #
18670     (write-buffered *(ebp+8) "  # . prologue\n")
18671     (write-buffered *(ebp+8) "  55/push-ebp\n")
18672     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
18673 $emit-subx-prologue:end:
18674     # . epilogue
18675     89/<- %esp 5/r32/ebp
18676     5d/pop-to-ebp
18677     c3/return
18678 
18679 emit-subx-epilogue:  # out: (addr buffered-file)
18680     # . prologue
18681     55/push-ebp
18682     89/<- %ebp 4/r32/esp
18683     #
18684     (write-buffered *(ebp+8) "  # . epilogue\n")
18685     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
18686     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
18687     (write-buffered *(ebp+8) "  c3/return\n")
18688 $emit-subx-epilogue:end:
18689     # . epilogue
18690     89/<- %esp 5/r32/ebp
18691     5d/pop-to-ebp
18692     c3/return