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 
    7 # == Goals
    8 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
    9 # a bad pointer. (Requires strong type safety.)
   10 # 2. Do as little as possible to achieve goal 1. The translator should be
   11 # implementable in machine code.
   12 #   - minimize impedance mismatch between source language and SubX target
   13 #     (e.g. programmer manages registers manually)
   14 #   - checks over syntax
   15 #     (e.g. programmer's register allocation is checked)
   16 #   - runtime checks to avoid complex static analysis
   17 #     (e.g. array indexing always checks bounds)
   18 
   19 # == Language description
   20 # A program is a sequence of function and type definitions.
   21 #
   22 # Function example:
   23 #   fn foo n: int -> result/eax: int {
   24 #     ...
   25 #   }
   26 #
   27 # Functions consist of a name, optional inputs, optional outputs and a block.
   28 #
   29 # Function inputs and outputs are variables. All variables have a type and
   30 # storage specifier. They can be placed either in memory (on the stack) or in
   31 # one of 6 named registers.
   32 #   eax ecx edx ebx esi edi
   33 # Variables in registers must be primitive 32-bit types.
   34 # Variables not explicitly placed in a register are on the stack.
   35 #
   36 # Function inputs are always passed in memory (on the stack), while outputs
   37 # are always returned in registers.
   38 #
   39 # Blocks mostly consist of statements.
   40 #
   41 # Statements mostly consist of a name, optional inputs and optional outputs.
   42 #
   43 # Statement inputs are variables or literals. Variables need to specify type
   44 # (and storage) the first time they're mentioned but not later.
   45 #
   46 # Statement outputs, like function outputs, must be variables in registers.
   47 #
   48 # Statement names must be either primitives or user-defined functions.
   49 #
   50 # Primitives can write to any register.
   51 # User-defined functions only write to hard-coded registers. Outputs of each
   52 # call must have the same registers as in the function definition.
   53 #
   54 # There are some other statement types:
   55 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   56 #     prefixed with a label name and ':'
   57 #       - {
   58 #           ...
   59 #         }
   60 #       - foo: {
   61 #           ...
   62 #         }
   63 #
   64 #   - variable definitions on the stack. E.g.:
   65 #       - var foo: int
   66 #       - var bar: (array int 3)
   67 #     There's no initializer; variables are automatically initialized.
   68 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   69 #
   70 #   - variables definitions in a register. E.g.:
   71 #       - var foo/eax: int <- add bar 1
   72 #     The initializer is mandatory and must be a valid instruction that writes
   73 #     a single output to the right register. In practice registers will
   74 #     usually be either initialized by primitives or copied from eax.
   75 #       - var eax: int <- foo bar quux
   76 #         var floo/ecx: int <- copy eax
   77 #
   78 # Still todo:
   79 #   global variables
   80 #   heap allocations (planned name: 'handle')
   81 #   user-defined types: 'type' for structs, 'choice' for unions
   82 #   short-lived 'address' type for efficiently writing inside nested structs
   83 #
   84 # We don't have 'handle' types yet, but we try to distinguish 'ref', 'handle'
   85 # and 'address' in comments. Their definitions are in layer 50, but really you
   86 # can ignore the distinctions on a first reading of this program.
   87 #
   88 # Formal types:
   89 #   A program is a linked list of functions
   90 #   A function contains:
   91 #     name: (handle array byte)
   92 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   93 #       data: (handle var)
   94 #       next: (handle list)
   95 #     outputs: linked list of vars
   96 #       data: (handle var)
   97 #       next: (handle list)
   98 #     body: (handle block)
   99 #   A var-type contains:
  100 #     name: (handle array byte)
  101 #     type: (handle tree type-id)
  102 #
  103 #   A statement can be:
  104 #     tag 0: a block
  105 #     tag 1: a simple statement (stmt1)
  106 #     tag 2: a variable defined on the stack
  107 #     tag 3: a variable defined in a register
  108 #
  109 #   A block contains:
  110 #     tag: 0
  111 #     statements: (handle list stmt)
  112 #     name: (handle array byte) -- starting with '$'
  113 #
  114 #   A regular statement contains:
  115 #     tag: 1
  116 #     operation: (handle array byte)
  117 #     inouts: (handle list operand)
  118 #     outputs: (handle list var)
  119 #
  120 #   A variable defined on the stack contains:
  121 #     tag: 2
  122 #     name: (handle array byte)
  123 #     type: (handle tree type-id)
  124 #
  125 #   A variable defined in a register contains:
  126 #     tag: 3
  127 #     name: (handle array byte)
  128 #     type: (handle tree type-id)
  129 #     reg: (handle array byte)
  130 
  131 # == Translation: managing the stack
  132 # Now that we know what the language looks like in the large, let's think
  133 # about how translation happens from the bottom up. One crucial piece of the
  134 # puzzle is how Mu will clean up variables defined on the stack for you.
  135 #
  136 # Assume that we maintain a 'functions' list while parsing source code. And a
  137 # 'primitives' list is a global constant. Both these contain enough information
  138 # to perform type-checking on function calls or primitive statements, respectively.
  139 #
  140 # Defining variables pushes them on a stack with the current block depth and
  141 # enough information about their location (stack offset or register).
  142 # Starting a block increments the current block id.
  143 # Each statement now has enough information to emit code for it.
  144 # Ending a block is where the magic happens:
  145 #   pop all variables at the current block depth
  146 #   emit code to restore all register variables introduced at the current depth
  147 #   emit code to clean up all stack variables at the current depth (just increment esp)
  148 #   decrement the current block depth
  149 #
  150 # Formal types:
  151 #   live-vars: stack of vars
  152 #   var:
  153 #     name: (handle array byte)
  154 #     type: (handle tree type-id)
  155 #     block: int
  156 #     stack-offset: int  (added to ebp)
  157 #     register: (handle array byte)
  158 #       either usual register names
  159 #       or '*' to indicate any register
  160 #   At most one of stack-offset or register-index must be non-zero.
  161 #   A register of '*' designates a variable _template_. Only legal in formal
  162 #   parameters for primitives.
  163 
  164 # == Translating a single function call
  165 # This one's easy. Assuming we've already checked things, we just drop the
  166 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  167 #
  168 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  169 # =>
  170 # (subx-name inout1 inout2 inout3)
  171 #
  172 # Formal types:
  173 #   functions: linked list of info
  174 #     name: (handle array byte)
  175 #     inouts: linked list of vars
  176 #     outputs: linked list of vars
  177 #     body: block (singleton linked list)
  178 #     subx-name: (handle array byte)
  179 
  180 # == Translating a single primitive instruction
  181 # A second crucial piece of the puzzle is how Mu converts fairly regular
  182 # primitives with their uniform syntax to SubX instructions with their gnarly
  183 # x86 details.
  184 #
  185 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  186 # them.
  187 # SubX instructions have rm32 and r32 operands.
  188 # The translation between them covers almost all the possibilities.
  189 #   Instructions with 1 inout may turn into ones with 1 rm32
  190 #     (e.g. incrementing a var on the stack)
  191 #   Instructions with 1 output may turn into ones with 1 rm32
  192 #     (e.g. incrementing a var in a register)
  193 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  194 #     (e.g. adding a var to a reg)
  195 #   2 inouts may turn into 1 rm32 and 1 r32
  196 #     (e.g. adding a reg to a var)
  197 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  198 #     (e.g. adding a constant to a var)
  199 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  200 #     (e.g. adding a constant to a reg)
  201 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  202 #     (special-case: divide edx:eax by a var or reg)
  203 # Observations:
  204 #   We always emit rm32. It may be the first inout or the first output.
  205 #   We may emit r32 or imm32 or neither.
  206 #   When we emit r32 it may come from first inout or second inout or first output.
  207 #
  208 # Accordingly, the formal data structure for a primitive looks like this:
  209 #   primitives: linked list of info
  210 #     name: (handle array byte)
  211 #     mu-inouts: linked list of vars to check
  212 #     mu-outputs: linked list of vars to check; at most a singleton
  213 #     subx-name: (handle array byte)
  214 #     subx-rm32: enum arg-location
  215 #     subx-r32: enum arg-location
  216 #     subx-imm32: enum arg-location
  217 #     subx-disp32: enum arg-location
  218 #     output-is-write-only: boolean
  219 #   arg-location: enum
  220 #     0 means none
  221 #     1 means first inout
  222 #     2 means second inout
  223 #     3 means first output
  224 
  225 # == Translating a block
  226 # Emit block name if necessary
  227 # Emit '{'
  228 # When you encounter a statement, emit it as above
  229 # When you encounter a variable declaration
  230 #   emit any code needed for it (bzeros)
  231 #   push it on the var stack
  232 #   update register dict if necessary
  233 # When you encounter '}'
  234 #   While popping variables off the var stack until block id changes
  235 #     Emit code needed to clean up the stack
  236 #       either increment esp
  237 #       or pop into appropriate register
  238 
  239 # The rest is straightforward.
  240 
  241 == data
  242 
  243 Program:
  244 _Program-functions:  # (handle function)
  245   0/imm32
  246 _Program-functions->payload:
  247   0/imm32
  248 _Program-types:  # (handle typeinfo)
  249   0/imm32
  250 _Program-types->payload:
  251   0/imm32
  252 
  253 # Some constants for simulating the data structures described above.
  254 # Many constants here come with a type in a comment.
  255 #
  256 # Sometimes the type is of the value at that offset for the given type. For
  257 # example, if you start at a function record and move forward Function-inouts
  258 # bytes, you'll find a (handle list var).
  259 #
  260 # At other times, the type is of the constant itself. For example, the type of
  261 # the constant Function-size is (addr int). To get the size of a function,
  262 # look in *Function-size.
  263 
  264 Function-name:  # (handle array byte)
  265   0/imm32
  266 Function-inouts:  # (handle list var)
  267   8/imm32
  268 Function-outputs:  # (handle list var)
  269   0x10/imm32
  270 Function-body:  # (handle block)
  271   0x18/imm32
  272 Function-next:  # (handle function)
  273   0x20/imm32
  274 Function-size:  # (addr int)
  275   0x28/imm32/40
  276 
  277 Primitive-name:  # (handle array byte)
  278   0/imm32
  279 Primitive-inouts:  # (handle list var)
  280   8/imm32
  281 Primitive-outputs:  # (handle list var)
  282   0x10/imm32
  283 Primitive-subx-name:  # (handle array byte)
  284   0x18/imm32
  285 Primitive-subx-rm32:  # enum arg-location
  286   0x20/imm32
  287 Primitive-subx-r32:  # enum arg-location
  288   0x24/imm32
  289 Primitive-subx-imm32:  # enum arg-location
  290   0x28/imm32
  291 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  292   0x2c/imm32
  293 Primitive-output-is-write-only:  # boolean
  294   0x30/imm32
  295 Primitive-next:  # (handle function)
  296   0x34/imm32
  297 Primitive-size:  # (addr int)
  298   0x3c/imm32/60
  299 
  300 Stmt-tag:  # int
  301   0/imm32
  302 
  303 Block-stmts:  # (handle list stmt)
  304   4/imm32
  305 Block-var:  # (handle var)
  306   0xc/imm32
  307 
  308 Stmt1-operation:  # (handle array byte)
  309   4/imm32
  310 Stmt1-inouts:  # (handle stmt-var)
  311   0xc/imm32
  312 Stmt1-outputs:  # (handle stmt-var)
  313   0x14/imm32
  314 
  315 Vardef-var:  # (handle var)
  316   4/imm32
  317 
  318 Regvardef-operation:  # (handle array byte)
  319   4/imm32
  320 Regvardef-inouts:  # (handle stmt-var)
  321   0xc/imm32
  322 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  323   0x14/imm32
  324 
  325 Stmt-size:  # (addr int)
  326   0x1c/imm32
  327 
  328 Var-name:  # (handle array byte)
  329   0/imm32
  330 Var-type:  # (handle tree type-id)
  331   8/imm32
  332 Var-block-depth:  # int -- not available until code-generation time
  333   0x10/imm32
  334 Var-offset:  # int -- not available until code-generation time
  335   0x14/imm32
  336 Var-register:  # (handle array byte) -- name of a register
  337   0x18/imm32
  338 Var-size:  # (addr int)
  339   0x20/imm32
  340 
  341 List-value:  # (handle _)
  342   0/imm32
  343 List-next:  # (handle list _)
  344   8/imm32
  345 List-size:  # (addr int)
  346   0x10/imm32
  347 
  348 # A stmt-var is like a list of vars with call-site specific metadata
  349 Stmt-var-value:  # (handle var)
  350   0/imm32
  351 Stmt-var-next:  # (handle stmt-var)
  352   8/imm32
  353 Stmt-var-is-deref:  # boolean
  354   0x10/imm32
  355 Stmt-var-size:  # (addr int)
  356   0x14/imm32
  357 
  358 # A live-var is a var augmented with information needed for tracking live
  359 # variables.
  360 Live-var-value:  # (handle var)
  361   0/imm32
  362 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  363   8/imm32
  364 Live-var-size:  # (addr int)
  365   0xc/imm32
  366 
  367 # Types are expressed as trees (s-expressions) of type-ids (ints).
  368 
  369 Tree-is-atom:  # boolean
  370   0/imm32
  371 # if left-is-atom?
  372 Tree-value:  # type-id
  373   4/imm32
  374 # unless left-is-atom?
  375 Tree-left:  # (addr tree type-id)
  376   4/imm32
  377 Tree-right:  # (addr tree type-id)
  378   0xc/imm32
  379 #
  380 Tree-size:  # (addr int)
  381   0x14/imm32
  382 
  383 # Types
  384 
  385 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  386 Type-id:  # (stream (addr array byte))
  387   0x20/imm32/write
  388   0/imm32/read
  389   0x100/imm32/size
  390   # data
  391   "literal"/imm32  # 0: value is just the name
  392   "int"/imm32  # 1
  393   "addr"/imm32  # 2
  394   "array"/imm32  # 3
  395   "handle"/imm32  # 4
  396   "boolean"/imm32  # 5
  397   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  398   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  399   # 0x20
  400   "byte"/imm32  # 8
  401           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  402   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  403   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  404   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  405   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  406   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  407   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  408 
  409 # == Type definitions
  410 # Program->types contains some typeinfo for each type definition.
  411 # Types contain vars with types, but can't specify registers.
  412 Typeinfo-id:  # type-id
  413   0/imm32
  414 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  415   4/imm32
  416 # Total size must be >= 0
  417 # During parsing it may take on two additional values:
  418 #   -2: not yet initialized
  419 #   -1: in process of being computed
  420 # See populate-mu-type-sizes for details.
  421 Typeinfo-total-size-in-bytes:  # int
  422   0xc/imm32
  423 Typeinfo-next:  # (handle typeinfo)
  424   0x10/imm32
  425 Typeinfo-size:  # (addr int)
  426   0x18/imm32
  427 
  428 # Each entry in the typeinfo->fields table has a pointer to a string and a
  429 # pointer to a typeinfo-entry.
  430 Typeinfo-fields-row-size:  # (addr int)
  431   0x10/imm32
  432 
  433 # typeinfo-entry objects have information about a field in a single record type
  434 #
  435 # each field of a type is represented using two var's:
  436 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  437 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  438 # computing the output happens after parsing; in the meantime we preserve the
  439 # order of fields in the 'index' field.
  440 Typeinfo-entry-input-var:  # (handle var)
  441   0/imm32
  442 Typeinfo-entry-index:  # int
  443   8/imm32
  444 Typeinfo-entry-output-var:  # (handle var)
  445   0xc/imm32
  446 Typeinfo-entry-size:  # (addr int)
  447   0x14/imm32
  448 
  449 == code
  450 
  451 Entry:
  452     # . prologue
  453     89/<- %ebp 4/r32/esp
  454     (new-segment *Heap-size Heap)
  455     # if (argv[1] == "test') run-tests()
  456     {
  457       # if (argc <= 1) break
  458       81 7/subop/compare *ebp 1/imm32
  459       7e/jump-if-<= break/disp8
  460       # if (argv[1] != "test") break
  461       (kernel-string-equal? *(ebp+8) "test")  # => eax
  462       3d/compare-eax-and 0/imm32/false
  463       74/jump-if-= break/disp8
  464       #
  465       (run-tests)
  466       # syscall(exit, *Num-test-failures)
  467       8b/-> *Num-test-failures 3/r32/ebx
  468       eb/jump $mu-main:end/disp8
  469     }
  470     # otherwise convert Stdin
  471     (convert-mu Stdin Stdout Stderr 0)
  472     (flush Stdout)
  473     # syscall(exit, 0)
  474     bb/copy-to-ebx 0/imm32
  475 $mu-main:end:
  476     e8/call syscall_exit/disp32
  477 
  478 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  479     # . prologue
  480     55/push-ebp
  481     89/<- %ebp 4/r32/esp
  482     # initialize global data structures
  483     c7 0/subop/copy *Next-block-index 1/imm32
  484     c7 0/subop/copy *Type-id 0x24/imm32  # stream-write
  485     c7 0/subop/copy *_Program-functions 0/imm32
  486     c7 0/subop/copy *_Program-functions->payload 0/imm32
  487     c7 0/subop/copy *_Program-types 0/imm32
  488     c7 0/subop/copy *_Program-types->payload 0/imm32
  489     #
  490     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  491     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  492 #?     (dump-typeinfos "=== typeinfos\n")
  493     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  494     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  495 $convert-mu:end:
  496     # . epilogue
  497     89/<- %esp 5/r32/ebp
  498     5d/pop-to-ebp
  499     c3/return
  500 
  501 test-convert-empty-input:
  502     # empty input => empty output
  503     # . prologue
  504     55/push-ebp
  505     89/<- %ebp 4/r32/esp
  506     # setup
  507     (clear-stream _test-input-stream)
  508     (clear-stream $_test-input-buffered-file->buffer)
  509     (clear-stream _test-output-stream)
  510     (clear-stream $_test-output-buffered-file->buffer)
  511     #
  512     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  513     (flush _test-output-buffered-file)
  514     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  515     # . epilogue
  516     89/<- %esp 5/r32/ebp
  517     5d/pop-to-ebp
  518     c3/return
  519 
  520 test-convert-function-skeleton:
  521     # . prologue
  522     55/push-ebp
  523     89/<- %ebp 4/r32/esp
  524     # setup
  525     (clear-stream _test-input-stream)
  526     (clear-stream $_test-input-buffered-file->buffer)
  527     (clear-stream _test-output-stream)
  528     (clear-stream $_test-output-buffered-file->buffer)
  529     #
  530     (write _test-input-stream "fn foo {\n")
  531     (write _test-input-stream "}\n")
  532     # convert
  533     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  534     (flush _test-output-buffered-file)
  535 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  541     # check output
  542     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  543     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  544     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  545     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  546     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  547     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  548     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  549     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  550     # . epilogue
  551     89/<- %esp 5/r32/ebp
  552     5d/pop-to-ebp
  553     c3/return
  554 
  555 test-convert-multiple-function-skeletons:
  556     # . prologue
  557     55/push-ebp
  558     89/<- %ebp 4/r32/esp
  559     # setup
  560     (clear-stream _test-input-stream)
  561     (clear-stream $_test-input-buffered-file->buffer)
  562     (clear-stream _test-output-stream)
  563     (clear-stream $_test-output-buffered-file->buffer)
  564     #
  565     (write _test-input-stream "fn foo {\n")
  566     (write _test-input-stream "}\n")
  567     (write _test-input-stream "fn bar {\n")
  568     (write _test-input-stream "}\n")
  569     # convert
  570     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  571     (flush _test-output-buffered-file)
  572 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  578     # check first function
  579     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  580     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  581     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  582     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  583     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  584     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  585     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  586     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  587     # check second function
  588     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  589     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  590     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  591     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  592     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  593     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  594     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  595     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  596     # . epilogue
  597     89/<- %esp 5/r32/ebp
  598     5d/pop-to-ebp
  599     c3/return
  600 
  601 test-convert-function-with-arg:
  602     # . prologue
  603     55/push-ebp
  604     89/<- %ebp 4/r32/esp
  605     # setup
  606     (clear-stream _test-input-stream)
  607     (clear-stream $_test-input-buffered-file->buffer)
  608     (clear-stream _test-output-stream)
  609     (clear-stream $_test-output-buffered-file->buffer)
  610     #
  611     (write _test-input-stream "fn foo n: int {\n")
  612     (write _test-input-stream "}\n")
  613     # convert
  614     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  615     (flush _test-output-buffered-file)
  616 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  622     # check output
  623     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  624     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  625     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  626     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  627     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  628     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  629     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  630     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  631     # . epilogue
  632     89/<- %esp 5/r32/ebp
  633     5d/pop-to-ebp
  634     c3/return
  635 
  636 test-convert-function-with-arg-and-body:
  637     # . prologue
  638     55/push-ebp
  639     89/<- %ebp 4/r32/esp
  640     # setup
  641     (clear-stream _test-input-stream)
  642     (clear-stream $_test-input-buffered-file->buffer)
  643     (clear-stream _test-output-stream)
  644     (clear-stream $_test-output-buffered-file->buffer)
  645     #
  646     (write _test-input-stream "fn foo n: int {\n")
  647     (write _test-input-stream "  increment n\n")
  648     (write _test-input-stream "}\n")
  649     # convert
  650     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  651     (flush _test-output-buffered-file)
  652 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  658     # check output
  659     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  660     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  661     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  662     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  663     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  664     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  665     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  666     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  667     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  668     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  669     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  670     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  671     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  672     # . epilogue
  673     89/<- %esp 5/r32/ebp
  674     5d/pop-to-ebp
  675     c3/return
  676 
  677 test-convert-function-distinguishes-args:
  678     # . prologue
  679     55/push-ebp
  680     89/<- %ebp 4/r32/esp
  681     # setup
  682     (clear-stream _test-input-stream)
  683     (clear-stream $_test-input-buffered-file->buffer)
  684     (clear-stream _test-output-stream)
  685     (clear-stream $_test-output-buffered-file->buffer)
  686     #
  687     (write _test-input-stream "fn foo a: int, b: int {\n")
  688     (write _test-input-stream "  increment b\n")
  689     (write _test-input-stream "}\n")
  690     # convert
  691     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  692     (flush _test-output-buffered-file)
  693 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  699     # check output
  700     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  701     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  702     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  703     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  704     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  705     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  706     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  707     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  708     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  709     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  710     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  711     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  712     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  713     # . epilogue
  714     89/<- %esp 5/r32/ebp
  715     5d/pop-to-ebp
  716     c3/return
  717 
  718 test-convert-function-returns-result:
  719     # . prologue
  720     55/push-ebp
  721     89/<- %ebp 4/r32/esp
  722     # setup
  723     (clear-stream _test-input-stream)
  724     (clear-stream $_test-input-buffered-file->buffer)
  725     (clear-stream _test-output-stream)
  726     (clear-stream $_test-output-buffered-file->buffer)
  727     #
  728     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  729     (write _test-input-stream "  result <- copy a\n")
  730     (write _test-input-stream "  result <- increment\n")
  731     (write _test-input-stream "}\n")
  732     # convert
  733     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  734     (flush _test-output-buffered-file)
  735 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  741     # check output
  742     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  743     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  744     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  745     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  746     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  748     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  749     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  750     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  751     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  752     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  753     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  754     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  755     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  756     # . epilogue
  757     89/<- %esp 5/r32/ebp
  758     5d/pop-to-ebp
  759     c3/return
  760 
  761 test-convert-function-with-literal-arg:
  762     # . prologue
  763     55/push-ebp
  764     89/<- %ebp 4/r32/esp
  765     # setup
  766     (clear-stream _test-input-stream)
  767     (clear-stream $_test-input-buffered-file->buffer)
  768     (clear-stream _test-output-stream)
  769     (clear-stream $_test-output-buffered-file->buffer)
  770     #
  771     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  772     (write _test-input-stream "  result <- copy a\n")
  773     (write _test-input-stream "  result <- add 1\n")
  774     (write _test-input-stream "}\n")
  775     # convert
  776     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  777     (flush _test-output-buffered-file)
  778 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  784     # check output
  785     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  786     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  787     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  788     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  789     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  790     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  791     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  792     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  793     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  794     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  795     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  796     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  797     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  798     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  799     # . epilogue
  800     89/<- %esp 5/r32/ebp
  801     5d/pop-to-ebp
  802     c3/return
  803 
  804 test-convert-function-with-literal-arg-2:
  805     # . prologue
  806     55/push-ebp
  807     89/<- %ebp 4/r32/esp
  808     # setup
  809     (clear-stream _test-input-stream)
  810     (clear-stream $_test-input-buffered-file->buffer)
  811     (clear-stream _test-output-stream)
  812     (clear-stream $_test-output-buffered-file->buffer)
  813     #
  814     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  815     (write _test-input-stream "  result <- copy a\n")
  816     (write _test-input-stream "  result <- add 1\n")
  817     (write _test-input-stream "}\n")
  818     # convert
  819     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  820     (flush _test-output-buffered-file)
  821 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  827     # check output
  828     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  829     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  830     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  831     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  832     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  834     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  835     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  836     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  837     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  838     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  839     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  840     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  841     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  842     # . epilogue
  843     89/<- %esp 5/r32/ebp
  844     5d/pop-to-ebp
  845     c3/return
  846 
  847 test-convert-function-call-with-literal-arg:
  848     # . prologue
  849     55/push-ebp
  850     89/<- %ebp 4/r32/esp
  851     # setup
  852     (clear-stream _test-input-stream)
  853     (clear-stream $_test-input-buffered-file->buffer)
  854     (clear-stream _test-output-stream)
  855     (clear-stream $_test-output-buffered-file->buffer)
  856     #
  857     (write _test-input-stream "fn main -> result/ebx: int {\n")
  858     (write _test-input-stream "  result <- do-add 3 4\n")
  859     (write _test-input-stream "}\n")
  860     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  861     (write _test-input-stream "  result <- copy a\n")
  862     (write _test-input-stream "  result <- add b\n")
  863     (write _test-input-stream "}\n")
  864     # convert
  865     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  866     (flush _test-output-buffered-file)
  867 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  873     # check output
  874     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  875     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  876     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  877     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  878     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  879     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  880     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  881     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  882     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  883     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  884     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  885     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  886     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  887     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  888     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  889     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  890     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  891     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  892     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  893     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  894     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  895     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  896     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  897     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  898     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  899     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  900     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  901     # . epilogue
  902     89/<- %esp 5/r32/ebp
  903     5d/pop-to-ebp
  904     c3/return
  905 
  906 test-convert-function-with-local-var-in-mem:
  907     # . prologue
  908     55/push-ebp
  909     89/<- %ebp 4/r32/esp
  910     # setup
  911     (clear-stream _test-input-stream)
  912     (clear-stream $_test-input-buffered-file->buffer)
  913     (clear-stream _test-output-stream)
  914     (clear-stream $_test-output-buffered-file->buffer)
  915     #
  916     (write _test-input-stream "fn foo {\n")
  917     (write _test-input-stream "  var x: int\n")
  918     (write _test-input-stream "  increment x\n")
  919     (write _test-input-stream "}\n")
  920     # convert
  921     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  922     (flush _test-output-buffered-file)
  923 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  929     # check output
  930     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  931     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  932     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  933     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  934     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  935     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  936     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  937     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  938     (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")
  939     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  940     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  941     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  942     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  943     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  944     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  945     # . epilogue
  946     89/<- %esp 5/r32/ebp
  947     5d/pop-to-ebp
  948     c3/return
  949 
  950 test-local-var-in-mem-has-no-initializer:
  951     # . prologue
  952     55/push-ebp
  953     89/<- %ebp 4/r32/esp
  954     # setup
  955     (clear-stream _test-input-stream)
  956     (clear-stream $_test-input-buffered-file->buffer)
  957     (clear-stream _test-output-stream)
  958     (clear-stream $_test-output-buffered-file->buffer)
  959     (clear-stream _test-error-stream)
  960     (clear-stream $_test-error-buffered-file->buffer)
  961     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
  962     68/push 0/imm32
  963     68/push 0/imm32
  964     89/<- %edx 4/r32/esp
  965     (tailor-exit-descriptor %edx 0x10)
  966     #
  967     (write _test-input-stream "fn foo {\n")
  968     (write _test-input-stream "  var x: int <- copy 0\n")
  969     (write _test-input-stream "  increment x\n")
  970     (write _test-input-stream "}\n")
  971     # convert
  972     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
  973     # registers except esp clobbered at this point
  974     # restore ed
  975     89/<- %edx 4/r32/esp
  976     (flush _test-output-buffered-file)
  977     (flush _test-error-buffered-file)
  978 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
  984     # check output
  985     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
  986     (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")
  987     # check that stop(1) was called
  988     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
  989     # don't restore from ebp
  990     81 0/subop/add %esp 8/imm32
  991     # . epilogue
  992     5d/pop-to-ebp
  993     c3/return
  994 
  995 test-convert-function-with-local-var-with-compound-type-in-mem:
  996     # . prologue
  997     55/push-ebp
  998     89/<- %ebp 4/r32/esp
  999     # setup
 1000     (clear-stream _test-input-stream)
 1001     (clear-stream $_test-input-buffered-file->buffer)
 1002     (clear-stream _test-output-stream)
 1003     (clear-stream $_test-output-buffered-file->buffer)
 1004     #
 1005     (write _test-input-stream "fn foo {\n")
 1006     (write _test-input-stream "  var x: (addr int)\n")
 1007     (write _test-input-stream "  copy-to x, 0\n")
 1008     (write _test-input-stream "}\n")
 1009     # convert
 1010     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1011     (flush _test-output-buffered-file)
 1012 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1018     # check output
 1019     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1020     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1021     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1022     (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")
 1023     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1024     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1025     (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")
 1026     (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")
 1027     (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")
 1028     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1030     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1031     (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")
 1032     (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")
 1033     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1034     # . epilogue
 1035     89/<- %esp 5/r32/ebp
 1036     5d/pop-to-ebp
 1037     c3/return
 1038 
 1039 test-convert-function-with-local-var-in-reg:
 1040     # . prologue
 1041     55/push-ebp
 1042     89/<- %ebp 4/r32/esp
 1043     # setup
 1044     (clear-stream _test-input-stream)
 1045     (clear-stream $_test-input-buffered-file->buffer)
 1046     (clear-stream _test-output-stream)
 1047     (clear-stream $_test-output-buffered-file->buffer)
 1048     #
 1049     (write _test-input-stream "fn foo {\n")
 1050     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1051     (write _test-input-stream "  x <- increment\n")
 1052     (write _test-input-stream "}\n")
 1053     # convert
 1054     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1055     (flush _test-output-buffered-file)
 1056 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1062     # check output
 1063     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1064     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1065     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1066     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1067     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1069     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1070     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1071     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1072     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1073     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1074     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1075     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1076     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1077     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1078     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1079     # . epilogue
 1080     89/<- %esp 5/r32/ebp
 1081     5d/pop-to-ebp
 1082     c3/return
 1083 
 1084 test-convert-function-with-second-local-var-in-same-reg:
 1085     # . prologue
 1086     55/push-ebp
 1087     89/<- %ebp 4/r32/esp
 1088     # setup
 1089     (clear-stream _test-input-stream)
 1090     (clear-stream $_test-input-buffered-file->buffer)
 1091     (clear-stream _test-output-stream)
 1092     (clear-stream $_test-output-buffered-file->buffer)
 1093     #
 1094     (write _test-input-stream "fn foo {\n")
 1095     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1096     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1097     (write _test-input-stream "  y <- increment\n")
 1098     (write _test-input-stream "}\n")
 1099     # convert
 1100     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1101     (flush _test-output-buffered-file)
 1102 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1108     # check output
 1109     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1110     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1111     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1112     (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")
 1113     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1114     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1115     (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")
 1116     (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")
 1117     (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")
 1118     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1119     (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")
 1120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1123     (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")
 1124     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1126     # . epilogue
 1127     89/<- %esp 5/r32/ebp
 1128     5d/pop-to-ebp
 1129     c3/return
 1130 
 1131 test-convert-function-call:
 1132     # . prologue
 1133     55/push-ebp
 1134     89/<- %ebp 4/r32/esp
 1135     # setup
 1136     (clear-stream _test-input-stream)
 1137     (clear-stream $_test-input-buffered-file->buffer)
 1138     (clear-stream _test-output-stream)
 1139     (clear-stream $_test-output-buffered-file->buffer)
 1140     #
 1141     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1142     (write _test-input-stream "  result <- foo\n")
 1143     (write _test-input-stream "}\n")
 1144     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1145     (write _test-input-stream "  result <- copy 3\n")
 1146     (write _test-input-stream "}\n")
 1147     # convert
 1148     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1149     (flush _test-output-buffered-file)
 1150 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1156     # check output
 1157     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1158     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1159     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1160     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1161     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1162     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1163     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1164     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1165     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1166     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1167     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1168     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1169     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1170     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1171     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1172     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1173     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1174     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1175     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1176     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1177     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1178     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1179     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1180     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1181     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1182     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1183     # . epilogue
 1184     89/<- %esp 5/r32/ebp
 1185     5d/pop-to-ebp
 1186     c3/return
 1187 
 1188 test-convert-function-call-with-incorrect-inout-type:
 1189     # . prologue
 1190     55/push-ebp
 1191     89/<- %ebp 4/r32/esp
 1192     # setup
 1193     (clear-stream _test-input-stream)
 1194     (clear-stream $_test-input-buffered-file->buffer)
 1195     (clear-stream _test-output-stream)
 1196     (clear-stream $_test-output-buffered-file->buffer)
 1197     (clear-stream _test-error-stream)
 1198     (clear-stream $_test-error-buffered-file->buffer)
 1199     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1200     68/push 0/imm32
 1201     68/push 0/imm32
 1202     89/<- %edx 4/r32/esp
 1203     (tailor-exit-descriptor %edx 0x10)
 1204     #
 1205     (write _test-input-stream "fn f {\n")
 1206     (write _test-input-stream "  var x: int\n")
 1207     (write _test-input-stream "  g x\n")
 1208     (write _test-input-stream "}\n")
 1209     (write _test-input-stream "fn g a: foo {\n")
 1210     (write _test-input-stream "}\n")
 1211     # convert
 1212     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1213     # registers except esp clobbered at this point
 1214     # restore ed
 1215     89/<- %edx 4/r32/esp
 1216     (flush _test-output-buffered-file)
 1217     (flush _test-error-buffered-file)
 1218 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1224     # check output
 1225     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1226     (check-next-stream-line-equal _test-error-stream  "call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
 1227     # check that stop(1) was called
 1228     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1229     # don't restore from ebp
 1230     81 0/subop/add %esp 8/imm32
 1231     5d/pop-to-ebp
 1232     c3/return
 1233 
 1234 test-convert-function-call-with-too-few-inouts:
 1235     # . prologue
 1236     55/push-ebp
 1237     89/<- %ebp 4/r32/esp
 1238     # setup
 1239     (clear-stream _test-input-stream)
 1240     (clear-stream $_test-input-buffered-file->buffer)
 1241     (clear-stream _test-output-stream)
 1242     (clear-stream $_test-output-buffered-file->buffer)
 1243     (clear-stream _test-error-stream)
 1244     (clear-stream $_test-error-buffered-file->buffer)
 1245     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1246     68/push 0/imm32
 1247     68/push 0/imm32
 1248     89/<- %edx 4/r32/esp
 1249     (tailor-exit-descriptor %edx 0x10)
 1250     #
 1251     (write _test-input-stream "fn f {\n")
 1252     (write _test-input-stream "  g\n")
 1253     (write _test-input-stream "}\n")
 1254     (write _test-input-stream "fn g a: int {\n")
 1255     (write _test-input-stream "}\n")
 1256     # convert
 1257     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1258     # registers except esp clobbered at this point
 1259     # restore ed
 1260     89/<- %edx 4/r32/esp
 1261     (flush _test-output-buffered-file)
 1262     (flush _test-error-buffered-file)
 1263 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1269     # check output
 1270     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1271     (check-next-stream-line-equal _test-error-stream  "call g: too few inouts"  "F - test-convert-function-call-with-too-few-inouts: error message")
 1272     # check that stop(1) was called
 1273     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1274     # don't restore from ebp
 1275     81 0/subop/add %esp 8/imm32
 1276     5d/pop-to-ebp
 1277     c3/return
 1278 
 1279 test-convert-function-call-with-too-many-inouts:
 1280     # . prologue
 1281     55/push-ebp
 1282     89/<- %ebp 4/r32/esp
 1283     # setup
 1284     (clear-stream _test-input-stream)
 1285     (clear-stream $_test-input-buffered-file->buffer)
 1286     (clear-stream _test-output-stream)
 1287     (clear-stream $_test-output-buffered-file->buffer)
 1288     (clear-stream _test-error-stream)
 1289     (clear-stream $_test-error-buffered-file->buffer)
 1290     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1291     68/push 0/imm32
 1292     68/push 0/imm32
 1293     89/<- %edx 4/r32/esp
 1294     (tailor-exit-descriptor %edx 0x10)
 1295     #
 1296     (write _test-input-stream "fn f {\n")
 1297     (write _test-input-stream "  var x: int\n")
 1298     (write _test-input-stream "  g x\n")
 1299     (write _test-input-stream "}\n")
 1300     (write _test-input-stream "fn g {\n")
 1301     (write _test-input-stream "}\n")
 1302     # convert
 1303     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1304     # registers except esp clobbered at this point
 1305     # restore ed
 1306     89/<- %edx 4/r32/esp
 1307     (flush _test-output-buffered-file)
 1308     (flush _test-error-buffered-file)
 1309 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1315     # check output
 1316     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1317     (check-next-stream-line-equal _test-error-stream  "call g: too many inouts"  "F - test-convert-function-call-with-too-many-inouts: error message")
 1318     # check that stop(1) was called
 1319     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1320     # don't restore from ebp
 1321     81 0/subop/add %esp 8/imm32
 1322     5d/pop-to-ebp
 1323     c3/return
 1324 
 1325 test-convert-function-call-with-incorrect-output-type:
 1326     # . prologue
 1327     55/push-ebp
 1328     89/<- %ebp 4/r32/esp
 1329     # setup
 1330     (clear-stream _test-input-stream)
 1331     (clear-stream $_test-input-buffered-file->buffer)
 1332     (clear-stream _test-output-stream)
 1333     (clear-stream $_test-output-buffered-file->buffer)
 1334     (clear-stream _test-error-stream)
 1335     (clear-stream $_test-error-buffered-file->buffer)
 1336     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1337     68/push 0/imm32
 1338     68/push 0/imm32
 1339     89/<- %edx 4/r32/esp
 1340     (tailor-exit-descriptor %edx 0x10)
 1341     #
 1342     (write _test-input-stream "fn f {\n")
 1343     (write _test-input-stream "  var x/eax: int <- g\n")
 1344     (write _test-input-stream "}\n")
 1345     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1346     (write _test-input-stream "}\n")
 1347     # convert
 1348     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1349     # registers except esp clobbered at this point
 1350     # restore ed
 1351     89/<- %edx 4/r32/esp
 1352     (flush _test-output-buffered-file)
 1353     (flush _test-error-buffered-file)
 1354 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1360     # check output
 1361     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1362     (check-next-stream-line-equal _test-error-stream  "call g: type for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-type: error message")
 1363     # check that stop(1) was called
 1364     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1365     # don't restore from ebp
 1366     81 0/subop/add %esp 8/imm32
 1367     5d/pop-to-ebp
 1368     c3/return
 1369 
 1370 test-convert-function-call-with-too-few-outputs:
 1371     # . prologue
 1372     55/push-ebp
 1373     89/<- %ebp 4/r32/esp
 1374     # setup
 1375     (clear-stream _test-input-stream)
 1376     (clear-stream $_test-input-buffered-file->buffer)
 1377     (clear-stream _test-output-stream)
 1378     (clear-stream $_test-output-buffered-file->buffer)
 1379     (clear-stream _test-error-stream)
 1380     (clear-stream $_test-error-buffered-file->buffer)
 1381     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1382     68/push 0/imm32
 1383     68/push 0/imm32
 1384     89/<- %edx 4/r32/esp
 1385     (tailor-exit-descriptor %edx 0x10)
 1386     #
 1387     (write _test-input-stream "fn f {\n")
 1388     (write _test-input-stream "  g\n")
 1389     (write _test-input-stream "}\n")
 1390     (write _test-input-stream "fn g -> a/eax: int {\n")
 1391     (write _test-input-stream "}\n")
 1392     # convert
 1393     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1394     # registers except esp clobbered at this point
 1395     # restore ed
 1396     89/<- %edx 4/r32/esp
 1397     (flush _test-output-buffered-file)
 1398     (flush _test-error-buffered-file)
 1399 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1405     # check output
 1406     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1407     (check-next-stream-line-equal _test-error-stream  "call g: too few outputs"  "F - test-convert-function-call-with-too-few-outputs: error message")
 1408     # check that stop(1) was called
 1409     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1410     # don't restore from ebp
 1411     81 0/subop/add %esp 8/imm32
 1412     5d/pop-to-ebp
 1413     c3/return
 1414 
 1415 test-convert-function-call-with-too-many-outputs:
 1416     # . prologue
 1417     55/push-ebp
 1418     89/<- %ebp 4/r32/esp
 1419     # setup
 1420     (clear-stream _test-input-stream)
 1421     (clear-stream $_test-input-buffered-file->buffer)
 1422     (clear-stream _test-output-stream)
 1423     (clear-stream $_test-output-buffered-file->buffer)
 1424     (clear-stream _test-error-stream)
 1425     (clear-stream $_test-error-buffered-file->buffer)
 1426     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1427     68/push 0/imm32
 1428     68/push 0/imm32
 1429     89/<- %edx 4/r32/esp
 1430     (tailor-exit-descriptor %edx 0x10)
 1431     #
 1432     (write _test-input-stream "fn f {\n")
 1433     (write _test-input-stream "  var x/eax: int <- g\n")
 1434     (write _test-input-stream "}\n")
 1435     (write _test-input-stream "fn g {\n")
 1436     (write _test-input-stream "}\n")
 1437     # convert
 1438     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1439     # registers except esp clobbered at this point
 1440     # restore ed
 1441     89/<- %edx 4/r32/esp
 1442     (flush _test-output-buffered-file)
 1443     (flush _test-error-buffered-file)
 1444 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1450     # check output
 1451     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1452     (check-next-stream-line-equal _test-error-stream  "call g: too many outputs"  "F - test-convert-function-call-with-too-many-outputs: error message")
 1453     # check that stop(1) was called
 1454     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1455     # don't restore from ebp
 1456     81 0/subop/add %esp 8/imm32
 1457     5d/pop-to-ebp
 1458     c3/return
 1459 
 1460 test-convert-function-call-with-incorrect-output-register:
 1461     # . prologue
 1462     55/push-ebp
 1463     89/<- %ebp 4/r32/esp
 1464     # setup
 1465     (clear-stream _test-input-stream)
 1466     (clear-stream $_test-input-buffered-file->buffer)
 1467     (clear-stream _test-output-stream)
 1468     (clear-stream $_test-output-buffered-file->buffer)
 1469     (clear-stream _test-error-stream)
 1470     (clear-stream $_test-error-buffered-file->buffer)
 1471     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1472     68/push 0/imm32
 1473     68/push 0/imm32
 1474     89/<- %edx 4/r32/esp
 1475     (tailor-exit-descriptor %edx 0x10)
 1476     #
 1477     (write _test-input-stream "fn f {\n")
 1478     (write _test-input-stream "  var x/ecx: int <- g\n")
 1479     (write _test-input-stream "}\n")
 1480     (write _test-input-stream "fn g -> a/eax: int {\n")
 1481     (write _test-input-stream "}\n")
 1482     # convert
 1483     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1484     # registers except esp clobbered at this point
 1485     # restore ed
 1486     89/<- %edx 4/r32/esp
 1487     (flush _test-output-buffered-file)
 1488     (flush _test-error-buffered-file)
 1489 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1495     # check output
 1496     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1497     (check-next-stream-line-equal _test-error-stream  "call g: register for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-register: error message")
 1498     # check that stop(1) was called
 1499     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1500     # don't restore from ebp
 1501     81 0/subop/add %esp 8/imm32
 1502     5d/pop-to-ebp
 1503     c3/return
 1504 
 1505 test-convert-function-with-local-var-dereferenced:
 1506     # . prologue
 1507     55/push-ebp
 1508     89/<- %ebp 4/r32/esp
 1509     # setup
 1510     (clear-stream _test-input-stream)
 1511     (clear-stream $_test-input-buffered-file->buffer)
 1512     (clear-stream _test-output-stream)
 1513     (clear-stream $_test-output-buffered-file->buffer)
 1514     #
 1515     (write _test-input-stream "fn foo {\n")
 1516     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1517     (write _test-input-stream "  increment *x\n")
 1518     (write _test-input-stream "}\n")
 1519     # convert
 1520     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1521     (flush _test-output-buffered-file)
 1522 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1528     # check output
 1529     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1530     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1531     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1532     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1533     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1534     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1535     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1536     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1537     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1538     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1539     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1540     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1541     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1542     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1543     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1544     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1545     # . epilogue
 1546     89/<- %esp 5/r32/ebp
 1547     5d/pop-to-ebp
 1548     c3/return
 1549 
 1550 # variables of type 'byte' are not allowed on the stack
 1551 test-convert-function-with-byte-operations:
 1552     # . prologue
 1553     55/push-ebp
 1554     89/<- %ebp 4/r32/esp
 1555     # setup
 1556     (clear-stream _test-input-stream)
 1557     (clear-stream $_test-input-buffered-file->buffer)
 1558     (clear-stream _test-output-stream)
 1559     (clear-stream $_test-output-buffered-file->buffer)
 1560     #
 1561     (write _test-input-stream "fn foo {\n")
 1562     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 1563     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 1564     (write _test-input-stream "  y <- copy-byte x\n")
 1565     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 1566     (write _test-input-stream "  y <- copy-byte *z\n")
 1567     (write _test-input-stream "  copy-byte-to *z, x\n")
 1568     (write _test-input-stream "}\n")
 1569     # convert
 1570     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1571     (flush _test-output-buffered-file)
 1572 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1578     # check output
 1579     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 1580     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 1581     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 1582     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 1583     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 1584     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 1585     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 1586     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 1587     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 1588     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 1589     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 1590     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 1591     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 1592     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 1593     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 1594     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 1595     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 1596     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 1597     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 1598     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 1599     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 1600     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 1601     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 1602     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 1603     # . epilogue
 1604     89/<- %esp 5/r32/ebp
 1605     5d/pop-to-ebp
 1606     c3/return
 1607 
 1608 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 1609 test-copy-byte-var-from-fn-arg:
 1610     # . prologue
 1611     55/push-ebp
 1612     89/<- %ebp 4/r32/esp
 1613     # setup
 1614     (clear-stream _test-input-stream)
 1615     (clear-stream $_test-input-buffered-file->buffer)
 1616     (clear-stream _test-output-stream)
 1617     (clear-stream $_test-output-buffered-file->buffer)
 1618     #
 1619     (write _test-input-stream "fn foo x: byte, y: int {\n")
 1620     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 1621     (write _test-input-stream "  var b/eax: int <- copy y\n")
 1622     (write _test-input-stream "}\n")
 1623     # convert
 1624     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1625     (flush _test-output-buffered-file)
 1626 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1632     # check output
 1633     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 1634     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 1635     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 1636     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 1637     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 1638     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 1639     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 1640     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 1641     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 1642     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 1643     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 1644     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 1645     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 1646     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 1647     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 1648     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 1649     # . epilogue
 1650     89/<- %esp 5/r32/ebp
 1651     5d/pop-to-ebp
 1652     c3/return
 1653 
 1654 test-convert-compare-register-with-literal:
 1655     # . prologue
 1656     55/push-ebp
 1657     89/<- %ebp 4/r32/esp
 1658     # setup
 1659     (clear-stream _test-input-stream)
 1660     (clear-stream $_test-input-buffered-file->buffer)
 1661     (clear-stream _test-output-stream)
 1662     (clear-stream $_test-output-buffered-file->buffer)
 1663     #
 1664     (write _test-input-stream "fn foo {\n")
 1665     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1666     (write _test-input-stream "  compare x, 0\n")
 1667     (write _test-input-stream "}\n")
 1668     # convert
 1669     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1670     (flush _test-output-buffered-file)
 1671 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1677     # check output
 1678     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1679     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1680     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1681     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1682     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1683     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1684     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1685     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1686     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1687     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1688     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1689     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1690     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1691     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1692     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1693     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1694     # . epilogue
 1695     89/<- %esp 5/r32/ebp
 1696     5d/pop-to-ebp
 1697     c3/return
 1698 
 1699 test-unknown-variable:
 1700     # . prologue
 1701     55/push-ebp
 1702     89/<- %ebp 4/r32/esp
 1703     # setup
 1704     (clear-stream _test-input-stream)
 1705     (clear-stream $_test-input-buffered-file->buffer)
 1706     (clear-stream _test-output-stream)
 1707     (clear-stream $_test-output-buffered-file->buffer)
 1708     (clear-stream _test-error-stream)
 1709     (clear-stream $_test-error-buffered-file->buffer)
 1710     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1711     68/push 0/imm32
 1712     68/push 0/imm32
 1713     89/<- %edx 4/r32/esp
 1714     (tailor-exit-descriptor %edx 0x10)
 1715     #
 1716     (write _test-input-stream "fn foo {\n")
 1717     (write _test-input-stream "  compare x, 0\n")
 1718     (write _test-input-stream "}\n")
 1719     # convert
 1720     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1721     # registers except esp clobbered at this point
 1722     # restore ed
 1723     89/<- %edx 4/r32/esp
 1724     (flush _test-output-buffered-file)
 1725     (flush _test-error-buffered-file)
 1726 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1732     # check output
 1733     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 1734     (check-next-stream-line-equal _test-error-stream  "unknown variable 'x'"  "F - test-unknown-variable: error message")
 1735     # check that stop(1) was called
 1736     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 1737     # don't restore from ebp
 1738     81 0/subop/add %esp 8/imm32
 1739     # . epilogue
 1740     5d/pop-to-ebp
 1741     c3/return
 1742 
 1743 test-convert-function-with-local-var-in-block:
 1744     # . prologue
 1745     55/push-ebp
 1746     89/<- %ebp 4/r32/esp
 1747     # setup
 1748     (clear-stream _test-input-stream)
 1749     (clear-stream $_test-input-buffered-file->buffer)
 1750     (clear-stream _test-output-stream)
 1751     (clear-stream $_test-output-buffered-file->buffer)
 1752     #
 1753     (write _test-input-stream "fn foo {\n")
 1754     (write _test-input-stream "  {\n")
 1755     (write _test-input-stream "    var x: int\n")
 1756     (write _test-input-stream "    increment x\n")
 1757     (write _test-input-stream "  }\n")
 1758     (write _test-input-stream "}\n")
 1759     # convert
 1760     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1761     (flush _test-output-buffered-file)
 1762 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1768     # check output
 1769     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1770     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1771     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1772     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1773     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1775     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1777     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1778     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1779     (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")
 1780     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1781     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1782     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1784     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1785     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1786     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1787     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1788     # . epilogue
 1789     89/<- %esp 5/r32/ebp
 1790     5d/pop-to-ebp
 1791     c3/return
 1792 
 1793 test-convert-function-with-local-var-in-named-block:
 1794     # . prologue
 1795     55/push-ebp
 1796     89/<- %ebp 4/r32/esp
 1797     # setup
 1798     (clear-stream _test-input-stream)
 1799     (clear-stream $_test-input-buffered-file->buffer)
 1800     (clear-stream _test-output-stream)
 1801     (clear-stream $_test-output-buffered-file->buffer)
 1802     #
 1803     (write _test-input-stream "fn foo {\n")
 1804     (write _test-input-stream "  $bar: {\n")
 1805     (write _test-input-stream "    var x: int\n")
 1806     (write _test-input-stream "    increment x\n")
 1807     (write _test-input-stream "  }\n")
 1808     (write _test-input-stream "}\n")
 1809     # convert
 1810     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1811     (flush _test-output-buffered-file)
 1812 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1818     # check output
 1819     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1820     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1821     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1822     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1823     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1824     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1825     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1826     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1827     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1828     (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")
 1829     (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")
 1830     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1831     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1832     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1834     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1835     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1836     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1837     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1838     # . epilogue
 1839     89/<- %esp 5/r32/ebp
 1840     5d/pop-to-ebp
 1841     c3/return
 1842 
 1843 test-unknown-variable-in-named-block:
 1844     # . prologue
 1845     55/push-ebp
 1846     89/<- %ebp 4/r32/esp
 1847     # setup
 1848     (clear-stream _test-input-stream)
 1849     (clear-stream $_test-input-buffered-file->buffer)
 1850     (clear-stream _test-output-stream)
 1851     (clear-stream $_test-output-buffered-file->buffer)
 1852     (clear-stream _test-error-stream)
 1853     (clear-stream $_test-error-buffered-file->buffer)
 1854     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1855     68/push 0/imm32
 1856     68/push 0/imm32
 1857     89/<- %edx 4/r32/esp
 1858     (tailor-exit-descriptor %edx 0x10)
 1859     #
 1860     (write _test-input-stream "fn foo {\n")
 1861     (write _test-input-stream "  $a: {\n")
 1862     (write _test-input-stream "    compare x, 0\n")
 1863     (write _test-input-stream "  }\n")
 1864     (write _test-input-stream "}\n")
 1865     # convert
 1866     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1867     # registers except esp clobbered at this point
 1868     # restore ed
 1869     89/<- %edx 4/r32/esp
 1870     (flush _test-output-buffered-file)
 1871     (flush _test-error-buffered-file)
 1872 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1878     # check output
 1879     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 1880     (check-next-stream-line-equal _test-error-stream  "unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 1881     # check that stop(1) was called
 1882     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 1883     # don't restore from ebp
 1884     81 0/subop/add %esp 8/imm32
 1885     # . epilogue
 1886     5d/pop-to-ebp
 1887     c3/return
 1888 
 1889 test-always-shadow-outermost-reg-vars-in-function:
 1890     # . prologue
 1891     55/push-ebp
 1892     89/<- %ebp 4/r32/esp
 1893     # setup
 1894     (clear-stream _test-input-stream)
 1895     (clear-stream $_test-input-buffered-file->buffer)
 1896     (clear-stream _test-output-stream)
 1897     (clear-stream $_test-output-buffered-file->buffer)
 1898     #
 1899     (write _test-input-stream "fn foo {\n")
 1900     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1901     (write _test-input-stream "}\n")
 1902     # convert
 1903     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1904     (flush _test-output-buffered-file)
 1905 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1911     # check output
 1912     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1913     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1914     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1915     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1916     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1917     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1918     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1919     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1920     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1921     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1922     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1923     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1924     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1925     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1926     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1927     # . epilogue
 1928     89/<- %esp 5/r32/ebp
 1929     5d/pop-to-ebp
 1930     c3/return
 1931 
 1932 _pending-test-clobber-dead-local:
 1933     # . prologue
 1934     55/push-ebp
 1935     89/<- %ebp 4/r32/esp
 1936     # setup
 1937     (clear-stream _test-input-stream)
 1938     (clear-stream $_test-input-buffered-file->buffer)
 1939     (clear-stream _test-output-stream)
 1940     (clear-stream $_test-output-buffered-file->buffer)
 1941     #
 1942     (write _test-input-stream "fn foo {\n")
 1943     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1944     (write _test-input-stream "  {\n")
 1945     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1946     (write _test-input-stream "  }\n")
 1947     (write _test-input-stream "}\n")
 1948     # convert
 1949     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1950     (flush _test-output-buffered-file)
 1951 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1957     # check output
 1958     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 1959     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 1960     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 1961     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 1962     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 1963     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 1964     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 1965     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 1966     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 1967     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 1968     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 1969     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 1970     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 1971     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 1972     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 1973     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 1974     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 1975     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 1976     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 1977     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 1978     # . epilogue
 1979     89/<- %esp 5/r32/ebp
 1980     5d/pop-to-ebp
 1981     c3/return
 1982 
 1983 test-shadow-live-local:
 1984     # . prologue
 1985     55/push-ebp
 1986     89/<- %ebp 4/r32/esp
 1987     # setup
 1988     (clear-stream _test-input-stream)
 1989     (clear-stream $_test-input-buffered-file->buffer)
 1990     (clear-stream _test-output-stream)
 1991     (clear-stream $_test-output-buffered-file->buffer)
 1992     #
 1993     (write _test-input-stream "fn foo {\n")
 1994     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1995     (write _test-input-stream "  {\n")
 1996     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1997     (write _test-input-stream "  }\n")
 1998     (write _test-input-stream "  x <- increment\n")
 1999     (write _test-input-stream "}\n")
 2000     # convert
 2001     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2002     (flush _test-output-buffered-file)
 2003 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2009     # check output
 2010     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2011     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2012     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2013     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2014     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2015     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2016     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2017     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2018     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2019     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2020     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2021     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2022     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2023     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2024     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2025     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2026     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2027     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2028     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2029     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2030     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2031     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2032     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/21")
 2033     # . epilogue
 2034     89/<- %esp 5/r32/ebp
 2035     5d/pop-to-ebp
 2036     c3/return
 2037 
 2038 test-do-not-spill-same-register-in-block:
 2039     # . prologue
 2040     55/push-ebp
 2041     89/<- %ebp 4/r32/esp
 2042     # setup
 2043     (clear-stream _test-input-stream)
 2044     (clear-stream $_test-input-buffered-file->buffer)
 2045     (clear-stream _test-output-stream)
 2046     (clear-stream $_test-output-buffered-file->buffer)
 2047     #
 2048     (write _test-input-stream "fn foo {\n")
 2049     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2050     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2051     (write _test-input-stream "  y <- increment\n")
 2052     (write _test-input-stream "}\n")
 2053     # convert
 2054     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2055     (flush _test-output-buffered-file)
 2056 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2062     # check output
 2063     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2064     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2065     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2066     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2067     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2069     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2070     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2071     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2072     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2073     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2074     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2075     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2076     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2077     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2078     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2079     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2080     # . epilogue
 2081     89/<- %esp 5/r32/ebp
 2082     5d/pop-to-ebp
 2083     c3/return
 2084 
 2085 test-spill-different-register-in-block:
 2086     # . prologue
 2087     55/push-ebp
 2088     89/<- %ebp 4/r32/esp
 2089     # setup
 2090     (clear-stream _test-input-stream)
 2091     (clear-stream $_test-input-buffered-file->buffer)
 2092     (clear-stream _test-output-stream)
 2093     (clear-stream $_test-output-buffered-file->buffer)
 2094     #
 2095     (write _test-input-stream "fn foo {\n")
 2096     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2097     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2098     (write _test-input-stream "  y <- increment\n")
 2099     (write _test-input-stream "}\n")
 2100     # convert
 2101     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2102     (flush _test-output-buffered-file)
 2103 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2109     # check output
 2110     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2111     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2112     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2113     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2114     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2115     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2116     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2117     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2118     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2119     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2120     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2121     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2122     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2123     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2124     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2125     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2126     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2127     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2128     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2129     # . epilogue
 2130     89/<- %esp 5/r32/ebp
 2131     5d/pop-to-ebp
 2132     c3/return
 2133 
 2134 test-shadow-live-output:
 2135     # . prologue
 2136     55/push-ebp
 2137     89/<- %ebp 4/r32/esp
 2138     # setup
 2139     (clear-stream _test-input-stream)
 2140     (clear-stream $_test-input-buffered-file->buffer)
 2141     (clear-stream _test-output-stream)
 2142     (clear-stream $_test-output-buffered-file->buffer)
 2143     #
 2144     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2145     (write _test-input-stream "  x <- copy 3\n")
 2146     (write _test-input-stream "  {\n")
 2147     (write _test-input-stream "    var y/ecx: int <- copy 4\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-live-output/0")
 2162     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2163     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2164     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2165     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2167     (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
 2168     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2169     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2170     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2171     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2172     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2173     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2174     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2175     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2176     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2178     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2179     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2180     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2181     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2182     # . epilogue
 2183     89/<- %esp 5/r32/ebp
 2184     5d/pop-to-ebp
 2185     c3/return
 2186 
 2187 test-local-clobbered-by-output:
 2188     # also doesn't spill
 2189     # . prologue
 2190     55/push-ebp
 2191     89/<- %ebp 4/r32/esp
 2192     # setup
 2193     (clear-stream _test-input-stream)
 2194     (clear-stream $_test-input-buffered-file->buffer)
 2195     (clear-stream _test-output-stream)
 2196     (clear-stream $_test-output-buffered-file->buffer)
 2197     #
 2198     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2199     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2200     (write _test-input-stream "  x <- copy y\n")
 2201     (write _test-input-stream "}\n")
 2202     # convert
 2203     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2204     (flush _test-output-buffered-file)
 2205 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2211     # check output
 2212     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-output/0")
 2213     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-output/1")
 2214     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-output/2")
 2215     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-output/3")
 2216     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-output/4")
 2217     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-output/5")
 2218     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-output/6")
 2219     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-output/7")
 2220     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-output/8")
 2221     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-output/9")
 2222     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-output/10")
 2223     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-output/11")
 2224     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-output/12")
 2225     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-output/13")
 2226     # . epilogue
 2227     89/<- %esp 5/r32/ebp
 2228     5d/pop-to-ebp
 2229     c3/return
 2230 
 2231 test-read-output:
 2232     # also doesn't spill
 2233     # . prologue
 2234     55/push-ebp
 2235     89/<- %ebp 4/r32/esp
 2236     # setup
 2237     (clear-stream _test-input-stream)
 2238     (clear-stream $_test-input-buffered-file->buffer)
 2239     (clear-stream _test-output-stream)
 2240     (clear-stream $_test-output-buffered-file->buffer)
 2241     #
 2242     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2243     (write _test-input-stream "  x <- copy 0x34\n")
 2244     (write _test-input-stream "  compare x, 0x35\n")
 2245     (write _test-input-stream "}\n")
 2246     # convert
 2247     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2248     (flush _test-output-buffered-file)
 2249 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2255     # check output
 2256     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2257     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2258     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2259     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2260     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2262     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2263     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2264     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2265     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2266     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2267     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2268     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2269     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2270     # . epilogue
 2271     89/<- %esp 5/r32/ebp
 2272     5d/pop-to-ebp
 2273     c3/return
 2274 
 2275 test-convert-function-with-branches-in-block:
 2276     # . prologue
 2277     55/push-ebp
 2278     89/<- %ebp 4/r32/esp
 2279     # setup
 2280     (clear-stream _test-input-stream)
 2281     (clear-stream $_test-input-buffered-file->buffer)
 2282     (clear-stream _test-output-stream)
 2283     (clear-stream $_test-output-buffered-file->buffer)
 2284     #
 2285     (write _test-input-stream "fn foo x: int {\n")
 2286     (write _test-input-stream "  {\n")
 2287     (write _test-input-stream "    break-if->=\n")
 2288     (write _test-input-stream "    loop-if-addr<\n")
 2289     (write _test-input-stream "    increment x\n")
 2290     (write _test-input-stream "    loop\n")
 2291     (write _test-input-stream "  }\n")
 2292     (write _test-input-stream "}\n")
 2293     # convert
 2294     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2295     (flush _test-output-buffered-file)
 2296 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2302     # check output
 2303     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2304     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2305     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2306     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 2307     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 2308     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 2309     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 2310     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 2311     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 2312     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 2313     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 2314     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 2315     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 2316     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 2317     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 2318     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 2319     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 2320     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 2321     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 2322     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 2323     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 2324     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 2325     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 2326     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 2327     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 2328     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 2329     # . epilogue
 2330     89/<- %esp 5/r32/ebp
 2331     5d/pop-to-ebp
 2332     c3/return
 2333 
 2334 test-convert-function-with-branches-in-named-block:
 2335     # . prologue
 2336     55/push-ebp
 2337     89/<- %ebp 4/r32/esp
 2338     # setup
 2339     (clear-stream _test-input-stream)
 2340     (clear-stream $_test-input-buffered-file->buffer)
 2341     (clear-stream _test-output-stream)
 2342     (clear-stream $_test-output-buffered-file->buffer)
 2343     #
 2344     (write _test-input-stream "fn foo x: int {\n")
 2345     (write _test-input-stream "  $bar: {\n")
 2346     (write _test-input-stream "    break-if->= $bar\n")
 2347     (write _test-input-stream "    loop-if-addr< $bar\n")
 2348     (write _test-input-stream "    increment x\n")
 2349     (write _test-input-stream "    loop\n")
 2350     (write _test-input-stream "  }\n")
 2351     (write _test-input-stream "}\n")
 2352     # convert
 2353     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2354     (flush _test-output-buffered-file)
 2355 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2361     # check output
 2362     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 2363     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 2364     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 2365     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 2366     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 2367     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 2368     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 2369     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 2370     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 2371     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 2372     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 2373     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 2374     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 2375     (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")
 2376     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 2377     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 2378     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 2379     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 2380     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 2381     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 2382     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 2383     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 2384     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 2385     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 2386     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 2387     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 2388     # . epilogue
 2389     89/<- %esp 5/r32/ebp
 2390     5d/pop-to-ebp
 2391     c3/return
 2392 
 2393 test-convert-function-with-var-in-nested-block:
 2394     # . prologue
 2395     55/push-ebp
 2396     89/<- %ebp 4/r32/esp
 2397     # setup
 2398     (clear-stream _test-input-stream)
 2399     (clear-stream $_test-input-buffered-file->buffer)
 2400     (clear-stream _test-output-stream)
 2401     (clear-stream $_test-output-buffered-file->buffer)
 2402     #
 2403     (write _test-input-stream "fn foo x: int {\n")
 2404     (write _test-input-stream "  {\n")
 2405     (write _test-input-stream "    {\n")
 2406     (write _test-input-stream "      var x: int\n")
 2407     (write _test-input-stream "      increment x\n")
 2408     (write _test-input-stream "    }\n")
 2409     (write _test-input-stream "  }\n")
 2410     (write _test-input-stream "}\n")
 2411     # convert
 2412     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2413     (flush _test-output-buffered-file)
 2414 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2420     # check output
 2421     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 2422     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 2423     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 2424     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 2425     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 2426     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 2427     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 2428     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 2429     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 2430     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 2431     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 2432     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 2433     (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")
 2434     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 2435     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 2436     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 2437     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 2438     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 2439     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 2440     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 2441     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 2442     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 2443     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 2444     # . epilogue
 2445     89/<- %esp 5/r32/ebp
 2446     5d/pop-to-ebp
 2447     c3/return
 2448 
 2449 test-convert-function-with-multiple-vars-in-nested-blocks:
 2450     # . prologue
 2451     55/push-ebp
 2452     89/<- %ebp 4/r32/esp
 2453     # setup
 2454     (clear-stream _test-input-stream)
 2455     (clear-stream $_test-input-buffered-file->buffer)
 2456     (clear-stream _test-output-stream)
 2457     (clear-stream $_test-output-buffered-file->buffer)
 2458     #
 2459     (write _test-input-stream "fn foo x: int {\n")
 2460     (write _test-input-stream "  {\n")
 2461     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 2462     (write _test-input-stream "    {\n")
 2463     (write _test-input-stream "      var y: int\n")
 2464     (write _test-input-stream "      x <- add y\n")
 2465     (write _test-input-stream "    }\n")
 2466     (write _test-input-stream "  }\n")
 2467     (write _test-input-stream "}\n")
 2468     # convert
 2469     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2470     (flush _test-output-buffered-file)
 2471 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2477     # check output
 2478     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 2479     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 2480     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 2481     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 2482     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 2483     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 2484     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 2485     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 2486     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 2487     (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")
 2488     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 2489     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 2490     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 2491     (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")
 2492     (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")
 2493     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 2494     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 2495     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 2496     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 2497     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 2498     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 2499     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 2500     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 2501     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 2502     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 2503     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 2504     # . epilogue
 2505     89/<- %esp 5/r32/ebp
 2506     5d/pop-to-ebp
 2507     c3/return
 2508 
 2509 test-convert-function-with-branches-and-local-vars:
 2510     # A conditional 'break' after a 'var' in a block is converted into a
 2511     # nested block that performs all necessary cleanup before jumping. This
 2512     # results in some ugly code duplication.
 2513     # . prologue
 2514     55/push-ebp
 2515     89/<- %ebp 4/r32/esp
 2516     # setup
 2517     (clear-stream _test-input-stream)
 2518     (clear-stream $_test-input-buffered-file->buffer)
 2519     (clear-stream _test-output-stream)
 2520     (clear-stream $_test-output-buffered-file->buffer)
 2521     #
 2522     (write _test-input-stream "fn foo {\n")
 2523     (write _test-input-stream "  {\n")
 2524     (write _test-input-stream "    var x: int\n")
 2525     (write _test-input-stream "    break-if->=\n")
 2526     (write _test-input-stream "    increment x\n")
 2527     (write _test-input-stream "  }\n")
 2528     (write _test-input-stream "}\n")
 2529     # convert
 2530     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2531     (flush _test-output-buffered-file)
 2532 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2538     # check output
 2539     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 2540     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 2541     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 2542     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 2543     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 2544     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 2545     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 2546     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 2547     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 2548     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 2549     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 2550     (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")
 2551     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 2552     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 2553     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 2554     (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")
 2555     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 2556     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 2557     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 2558     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 2559     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 2560     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 2561     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 2562     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 2563     # . epilogue
 2564     89/<- %esp 5/r32/ebp
 2565     5d/pop-to-ebp
 2566     c3/return
 2567 
 2568 test-convert-function-with-conditional-loops-and-local-vars:
 2569     # A conditional 'loop' after a 'var' in a block is converted into a nested
 2570     # block that performs all necessary cleanup before jumping. This results
 2571     # in some ugly code duplication.
 2572     # . prologue
 2573     55/push-ebp
 2574     89/<- %ebp 4/r32/esp
 2575     # setup
 2576     (clear-stream _test-input-stream)
 2577     (clear-stream $_test-input-buffered-file->buffer)
 2578     (clear-stream _test-output-stream)
 2579     (clear-stream $_test-output-buffered-file->buffer)
 2580     #
 2581     (write _test-input-stream "fn foo {\n")
 2582     (write _test-input-stream "  {\n")
 2583     (write _test-input-stream "    var x: int\n")
 2584     (write _test-input-stream "    loop-if->=\n")
 2585     (write _test-input-stream "    increment x\n")
 2586     (write _test-input-stream "  }\n")
 2587     (write _test-input-stream "}\n")
 2588     # convert
 2589     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2590     (flush _test-output-buffered-file)
 2591 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2597     # check output
 2598     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 2599     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 2600     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 2601     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 2602     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 2603     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 2604     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 2605     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 2606     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 2607     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 2608     (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")
 2609     (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")
 2610     (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")
 2611     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2612     (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")
 2613     (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")
 2614     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2615     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2616     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2617     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2618     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2619     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2620     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2621     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2622     # . epilogue
 2623     89/<- %esp 5/r32/ebp
 2624     5d/pop-to-ebp
 2625     c3/return
 2626 
 2627 test-convert-function-with-unconditional-loops-and-local-vars:
 2628     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2629     # regular block cleanup. Any instructions after 'loop' are dead and
 2630     # therefore skipped.
 2631     # . prologue
 2632     55/push-ebp
 2633     89/<- %ebp 4/r32/esp
 2634     # setup
 2635     (clear-stream _test-input-stream)
 2636     (clear-stream $_test-input-buffered-file->buffer)
 2637     (clear-stream _test-output-stream)
 2638     (clear-stream $_test-output-buffered-file->buffer)
 2639     #
 2640     (write _test-input-stream "fn foo {\n")
 2641     (write _test-input-stream "  {\n")
 2642     (write _test-input-stream "    var x: int\n")
 2643     (write _test-input-stream "    loop\n")
 2644     (write _test-input-stream "    increment x\n")
 2645     (write _test-input-stream "  }\n")
 2646     (write _test-input-stream "}\n")
 2647     # convert
 2648     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2649     (flush _test-output-buffered-file)
 2650 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2656     # check output
 2657     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2658     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2659     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2660     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2661     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2662     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2663     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2664     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2665     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2666     (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")
 2667     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2668     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2669     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2670     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2671     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2672     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2673     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2674     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2675     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2676     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2677     # . epilogue
 2678     89/<- %esp 5/r32/ebp
 2679     5d/pop-to-ebp
 2680     c3/return
 2681 
 2682 test-convert-function-with-branches-and-loops-and-local-vars:
 2683     # . prologue
 2684     55/push-ebp
 2685     89/<- %ebp 4/r32/esp
 2686     # setup
 2687     (clear-stream _test-input-stream)
 2688     (clear-stream $_test-input-buffered-file->buffer)
 2689     (clear-stream _test-output-stream)
 2690     (clear-stream $_test-output-buffered-file->buffer)
 2691     #
 2692     (write _test-input-stream "fn foo {\n")
 2693     (write _test-input-stream "  {\n")
 2694     (write _test-input-stream "    var x: int\n")
 2695     (write _test-input-stream "    break-if->=\n")
 2696     (write _test-input-stream "    increment x\n")
 2697     (write _test-input-stream "    loop\n")
 2698     (write _test-input-stream "  }\n")
 2699     (write _test-input-stream "}\n")
 2700     # convert
 2701     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2702     (flush _test-output-buffered-file)
 2703 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2709     # check output
 2710     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2711     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2712     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2713     (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")
 2714     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2716     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2717     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2718     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2719     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2720     (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")
 2721     (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")
 2722     (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")
 2723     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2724     (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")
 2725     (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")
 2726     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2727     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2728     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2729     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2730     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2731     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2732     (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")
 2733     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2734     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2735     # . epilogue
 2736     89/<- %esp 5/r32/ebp
 2737     5d/pop-to-ebp
 2738     c3/return
 2739 
 2740 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 2741     # . prologue
 2742     55/push-ebp
 2743     89/<- %ebp 4/r32/esp
 2744     # setup
 2745     (clear-stream _test-input-stream)
 2746     (clear-stream $_test-input-buffered-file->buffer)
 2747     (clear-stream _test-output-stream)
 2748     (clear-stream $_test-output-buffered-file->buffer)
 2749     #
 2750     (write _test-input-stream "fn foo {\n")
 2751     (write _test-input-stream "  a: {\n")
 2752     (write _test-input-stream "    var x: int\n")
 2753     (write _test-input-stream "    {\n")
 2754     (write _test-input-stream "      var y: int\n")
 2755     (write _test-input-stream "      break-if->= a\n")
 2756     (write _test-input-stream "      increment x\n")
 2757     (write _test-input-stream "      loop\n")
 2758     (write _test-input-stream "    }\n")
 2759     (write _test-input-stream "  }\n")
 2760     (write _test-input-stream "}\n")
 2761     # convert
 2762     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2763     (flush _test-output-buffered-file)
 2764 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2770     # check output
 2771     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 2772     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 2773     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 2774     (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")
 2775     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 2776     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 2777     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 2778     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 2779     (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")
 2780     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 2781     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 2782     (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")
 2783     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 2784     (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")
 2785     (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")
 2786     (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")
 2787     (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")
 2788     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 2789     (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")
 2790     (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")
 2791     (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")
 2792     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 2793     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 2794     (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")
 2795     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 2796     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 2797     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 2798     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 2799     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 2800     (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")
 2801     (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")
 2802     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 2803     # . epilogue
 2804     89/<- %esp 5/r32/ebp
 2805     5d/pop-to-ebp
 2806     c3/return
 2807 
 2808 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 2809     # . prologue
 2810     55/push-ebp
 2811     89/<- %ebp 4/r32/esp
 2812     # setup
 2813     (clear-stream _test-input-stream)
 2814     (clear-stream $_test-input-buffered-file->buffer)
 2815     (clear-stream _test-output-stream)
 2816     (clear-stream $_test-output-buffered-file->buffer)
 2817     # non-local conditional branch from a block without a local variable,
 2818     # unwinding a local on the stack
 2819     (write _test-input-stream "fn foo {\n")
 2820     (write _test-input-stream "  a: {\n")
 2821     (write _test-input-stream "    var x: int\n")
 2822     (write _test-input-stream "    {\n")
 2823     (write _test-input-stream "      break-if->= a\n")
 2824     (write _test-input-stream "    }\n")
 2825     (write _test-input-stream "  }\n")
 2826     (write _test-input-stream "}\n")
 2827     # convert
 2828     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2829     (flush _test-output-buffered-file)
 2830 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2836     # check output
 2837     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 2838     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 2839     (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")
 2840     (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")
 2841     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 2842     (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")
 2843     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 2844     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 2845     (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")
 2846     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 2847     (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")
 2848     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 2849     (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")
 2850     (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")
 2851     (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")
 2852     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 2853     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 2854     (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")
 2855     (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")
 2856     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 2857     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 2858     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 2859     (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")
 2860     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 2861     (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")
 2862     (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")
 2863     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 2864     # . epilogue
 2865     89/<- %esp 5/r32/ebp
 2866     5d/pop-to-ebp
 2867     c3/return
 2868 
 2869 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 2870     # . prologue
 2871     55/push-ebp
 2872     89/<- %ebp 4/r32/esp
 2873     # setup
 2874     (clear-stream _test-input-stream)
 2875     (clear-stream $_test-input-buffered-file->buffer)
 2876     (clear-stream _test-output-stream)
 2877     (clear-stream $_test-output-buffered-file->buffer)
 2878     # non-local unconditional branch from a block without a local variable,
 2879     # unwinding a local on the stack
 2880     (write _test-input-stream "fn foo {\n")
 2881     (write _test-input-stream "  a: {\n")
 2882     (write _test-input-stream "    var x: int\n")
 2883     (write _test-input-stream "    {\n")
 2884     (write _test-input-stream "      break a\n")
 2885     (write _test-input-stream "    }\n")
 2886     (write _test-input-stream "  }\n")
 2887     (write _test-input-stream "}\n")
 2888     # convert
 2889     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2890     (flush _test-output-buffered-file)
 2891 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2897     # check output
 2898     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 2899     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 2900     (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")
 2901     (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")
 2902     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 2903     (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")
 2904     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 2905     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 2906     (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")
 2907     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 2908     (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")
 2909     (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")
 2910     (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")
 2911     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 2912     (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")
 2913     (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")
 2914     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 2915     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 2916     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 2917     (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")
 2918     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 2919     (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")
 2920     (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")
 2921     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 2922     # . epilogue
 2923     89/<- %esp 5/r32/ebp
 2924     5d/pop-to-ebp
 2925     c3/return
 2926 
 2927 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 2928     # . prologue
 2929     55/push-ebp
 2930     89/<- %ebp 4/r32/esp
 2931     # setup
 2932     (clear-stream _test-input-stream)
 2933     (clear-stream $_test-input-buffered-file->buffer)
 2934     (clear-stream _test-output-stream)
 2935     (clear-stream $_test-output-buffered-file->buffer)
 2936     #
 2937     (write _test-input-stream "fn foo {\n")
 2938     (write _test-input-stream "  a: {\n")
 2939     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 2940     (write _test-input-stream "    {\n")
 2941     (write _test-input-stream "      break a\n")
 2942     (write _test-input-stream "    }\n")
 2943     (write _test-input-stream "  }\n")
 2944     (write _test-input-stream "}\n")
 2945     # convert
 2946     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2947     (flush _test-output-buffered-file)
 2948 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2954     # check output
 2955     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 2956     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 2957     (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")
 2958     (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")
 2959     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 2960     (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")
 2961     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 2962     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 2963     (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")
 2964     (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")
 2965     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 2966     (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")
 2967     (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")
 2968     (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")
 2969     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 2970     (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")
 2971     (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")
 2972     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 2973     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 2974     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 2975     (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")
 2976     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 2977     (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")
 2978     (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")
 2979     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 2980     # . epilogue
 2981     89/<- %esp 5/r32/ebp
 2982     5d/pop-to-ebp
 2983     c3/return
 2984 
 2985 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 2986     # . prologue
 2987     55/push-ebp
 2988     89/<- %ebp 4/r32/esp
 2989     # setup
 2990     (clear-stream _test-input-stream)
 2991     (clear-stream $_test-input-buffered-file->buffer)
 2992     (clear-stream _test-output-stream)
 2993     (clear-stream $_test-output-buffered-file->buffer)
 2994     #
 2995     (write _test-input-stream "fn foo {\n")
 2996     (write _test-input-stream "  a: {\n")
 2997     (write _test-input-stream "    var x: int\n")
 2998     (write _test-input-stream "    {\n")
 2999     (write _test-input-stream "      var y: int\n")
 3000     (write _test-input-stream "      break a\n")
 3001     (write _test-input-stream "      increment x\n")
 3002     (write _test-input-stream "    }\n")
 3003     (write _test-input-stream "  }\n")
 3004     (write _test-input-stream "}\n")
 3005     # convert
 3006     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3007     (flush _test-output-buffered-file)
 3008 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3014     # check output
 3015     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3016     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3017     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3018     (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")
 3019     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3021     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3022     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3023     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3024     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3025     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3026     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3027     (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")
 3028     (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")
 3029     (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")
 3030     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3031     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3032     (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")
 3033     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3034     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3035     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3036     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3037     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3038     (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")
 3039     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3040     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3041     # . epilogue
 3042     89/<- %esp 5/r32/ebp
 3043     5d/pop-to-ebp
 3044     c3/return
 3045 
 3046 test-convert-function-with-unconditional-break-and-local-vars:
 3047     # . prologue
 3048     55/push-ebp
 3049     89/<- %ebp 4/r32/esp
 3050     # setup
 3051     (clear-stream _test-input-stream)
 3052     (clear-stream $_test-input-buffered-file->buffer)
 3053     (clear-stream _test-output-stream)
 3054     (clear-stream $_test-output-buffered-file->buffer)
 3055     #
 3056     (write _test-input-stream "fn foo {\n")
 3057     (write _test-input-stream "  {\n")
 3058     (write _test-input-stream "    var x: int\n")
 3059     (write _test-input-stream "    {\n")
 3060     (write _test-input-stream "      var y: int\n")
 3061     (write _test-input-stream "      break\n")
 3062     (write _test-input-stream "      increment x\n")
 3063     (write _test-input-stream "    }\n")
 3064     (write _test-input-stream "  }\n")
 3065     (write _test-input-stream "}\n")
 3066     # convert
 3067     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3068     (flush _test-output-buffered-file)
 3069 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3075     # check output
 3076     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3077     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3078     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3079     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3080     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3081     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3082     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3083     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3084     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3085     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3086     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3087     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3088     (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")
 3089     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3090     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3091     (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")
 3092     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3093     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3094     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3095     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3096     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3097     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3098     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3099     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3100     # . epilogue
 3101     89/<- %esp 5/r32/ebp
 3102     5d/pop-to-ebp
 3103     c3/return
 3104 
 3105 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3106     # . prologue
 3107     55/push-ebp
 3108     89/<- %ebp 4/r32/esp
 3109     # setup
 3110     (clear-stream _test-input-stream)
 3111     (clear-stream $_test-input-buffered-file->buffer)
 3112     (clear-stream _test-output-stream)
 3113     (clear-stream $_test-output-buffered-file->buffer)
 3114     #
 3115     (write _test-input-stream "fn foo {\n")
 3116     (write _test-input-stream "  a: {\n")
 3117     (write _test-input-stream "    var x: int\n")
 3118     (write _test-input-stream "    {\n")
 3119     (write _test-input-stream "      var y: int\n")
 3120     (write _test-input-stream "      loop a\n")
 3121     (write _test-input-stream "      increment x\n")
 3122     (write _test-input-stream "    }\n")
 3123     (write _test-input-stream "  }\n")
 3124     (write _test-input-stream "}\n")
 3125     # convert
 3126     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3127     (flush _test-output-buffered-file)
 3128 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3134     # check output
 3135     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3136     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3137     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3138     (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")
 3139     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3140     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3141     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3142     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3143     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3144     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3145     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3146     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3147     (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")
 3148     (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")
 3149     (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")
 3150     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3151     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3152     (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")
 3153     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3154     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3155     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3156     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3157     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3158     (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")
 3159     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3160     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3161     # . epilogue
 3162     89/<- %esp 5/r32/ebp
 3163     5d/pop-to-ebp
 3164     c3/return
 3165 
 3166 test-convert-function-with-local-array-var-in-mem:
 3167     # . prologue
 3168     55/push-ebp
 3169     89/<- %ebp 4/r32/esp
 3170     # setup
 3171     (clear-stream _test-input-stream)
 3172     (clear-stream $_test-input-buffered-file->buffer)
 3173     (clear-stream _test-output-stream)
 3174     (clear-stream $_test-output-buffered-file->buffer)
 3175     #
 3176     (write _test-input-stream "fn foo {\n")
 3177     (write _test-input-stream "  var x: (array int 3)\n")
 3178     (write _test-input-stream "}\n")
 3179     # convert
 3180     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3181     (flush _test-output-buffered-file)
 3182 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3188     # check output
 3189     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3190     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3191     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3192     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3193     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3194     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3195     # define x
 3196     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3197     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3198     # reclaim x
 3199     (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")
 3200     #
 3201     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3202     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3203     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3204     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3205     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3206     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3207     # . epilogue
 3208     89/<- %esp 5/r32/ebp
 3209     5d/pop-to-ebp
 3210     c3/return
 3211 
 3212 # special-case for size(byte) when allocating array
 3213 test-convert-function-with-local-array-of-bytes-in-mem:
 3214     # . prologue
 3215     55/push-ebp
 3216     89/<- %ebp 4/r32/esp
 3217     # setup
 3218     (clear-stream _test-input-stream)
 3219     (clear-stream $_test-input-buffered-file->buffer)
 3220     (clear-stream _test-output-stream)
 3221     (clear-stream $_test-output-buffered-file->buffer)
 3222     #
 3223     (write _test-input-stream "fn foo {\n")
 3224     (write _test-input-stream "  var x: (array byte 3)\n")
 3225     (write _test-input-stream "}\n")
 3226     # convert
 3227     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3228     (flush _test-output-buffered-file)
 3229 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3235     # check output
 3236     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 3237     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 3238     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 3239     (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")
 3240     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 3241     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 3242     # define x
 3243     (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")
 3244     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 3245     # reclaim x
 3246     (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")
 3247     #
 3248     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 3249     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 3250     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 3251     (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")
 3252     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 3253     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 3254     # . epilogue
 3255     89/<- %esp 5/r32/ebp
 3256     5d/pop-to-ebp
 3257     c3/return
 3258 
 3259 test-convert-address:
 3260     # . prologue
 3261     55/push-ebp
 3262     89/<- %ebp 4/r32/esp
 3263     # setup
 3264     (clear-stream _test-input-stream)
 3265     (clear-stream $_test-input-buffered-file->buffer)
 3266     (clear-stream _test-output-stream)
 3267     (clear-stream $_test-output-buffered-file->buffer)
 3268     #
 3269     (write _test-input-stream "fn foo {\n")
 3270     (write _test-input-stream "  var a: int\n")
 3271     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 3272     (write _test-input-stream "}\n")
 3273     # convert
 3274     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3275     (flush _test-output-buffered-file)
 3276 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3282     # check output
 3283     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 3284     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 3285     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 3286     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 3287     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 3288     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 3289     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 3290     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 3291     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 3292     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 3293     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 3294     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 3295     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 3296     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 3297     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 3298     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 3299     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 3300     # . epilogue
 3301     89/<- %esp 5/r32/ebp
 3302     5d/pop-to-ebp
 3303     c3/return
 3304 
 3305 test-convert-length-of-array:
 3306     # . prologue
 3307     55/push-ebp
 3308     89/<- %ebp 4/r32/esp
 3309     # setup
 3310     (clear-stream _test-input-stream)
 3311     (clear-stream $_test-input-buffered-file->buffer)
 3312     (clear-stream _test-output-stream)
 3313     (clear-stream $_test-output-buffered-file->buffer)
 3314     #
 3315     (write _test-input-stream "fn foo a: (addr array int) {\n")
 3316     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 3317     (write _test-input-stream "  var c/eax: int <- length b\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-length-of-array/0")
 3330     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 3331     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 3332     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 3333     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 3334     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 3335     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 3336     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 3337     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 3338     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 3339     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 3340     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 3341     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 3342     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 3343     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 3344     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 3345     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 3346     # . epilogue
 3347     89/<- %esp 5/r32/ebp
 3348     5d/pop-to-ebp
 3349     c3/return
 3350 
 3351 # special-case for size(byte) when computing array length
 3352 test-convert-length-of-array-of-bytes:
 3353     # . prologue
 3354     55/push-ebp
 3355     89/<- %ebp 4/r32/esp
 3356     # setup
 3357     (clear-stream _test-input-stream)
 3358     (clear-stream $_test-input-buffered-file->buffer)
 3359     (clear-stream _test-output-stream)
 3360     (clear-stream $_test-output-buffered-file->buffer)
 3361     #
 3362     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 3363     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 3364     (write _test-input-stream "  var c/eax: int <- length b\n")
 3365     (write _test-input-stream "}\n")
 3366     # convert
 3367     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3368     (flush _test-output-buffered-file)
 3369 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3375     # check output
 3376     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 3377     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 3378     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 3379     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 3380     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 3381     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 3382     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 3383     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 3384     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 3385     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 3386     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 3387     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 3388     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 3389     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 3390     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 3391     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 3392     # . epilogue
 3393     89/<- %esp 5/r32/ebp
 3394     5d/pop-to-ebp
 3395     c3/return
 3396 
 3397 test-convert-length-of-array-on-stack:
 3398     # . prologue
 3399     55/push-ebp
 3400     89/<- %ebp 4/r32/esp
 3401     # setup
 3402     (clear-stream _test-input-stream)
 3403     (clear-stream $_test-input-buffered-file->buffer)
 3404     (clear-stream _test-output-stream)
 3405     (clear-stream $_test-output-buffered-file->buffer)
 3406     #
 3407     (write _test-input-stream "fn foo {\n")
 3408     (write _test-input-stream "  var a: (array int 3)\n")
 3409     (write _test-input-stream "  var b/eax: int <- length a\n")
 3410     (write _test-input-stream "}\n")
 3411     # convert
 3412     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3413     (flush _test-output-buffered-file)
 3414 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3420     # check output
 3421     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 3422     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 3423     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 3424     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 3425     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 3426     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 3427     # define x
 3428     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 3429     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 3430     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 3431     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 3432     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 3433     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 3434     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 3435     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 3436     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 3437     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 3438     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 3439     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 3440     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 3441     # . epilogue
 3442     89/<- %esp 5/r32/ebp
 3443     5d/pop-to-ebp
 3444     c3/return
 3445 
 3446 test-convert-index-into-array:
 3447     # . prologue
 3448     55/push-ebp
 3449     89/<- %ebp 4/r32/esp
 3450     # setup
 3451     (clear-stream _test-input-stream)
 3452     (clear-stream $_test-input-buffered-file->buffer)
 3453     (clear-stream _test-output-stream)
 3454     (clear-stream $_test-output-buffered-file->buffer)
 3455     #
 3456     (write _test-input-stream "fn foo {\n")
 3457     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3458     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3459     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3460     (write _test-input-stream "}\n")
 3461     # convert
 3462     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3463     (flush _test-output-buffered-file)
 3464 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3470     # check output
 3471     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 3472     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 3473     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 3474     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 3475     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 3476     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 3477     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 3478     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 3479     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 3480     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 3481     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/11")
 3482     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/13")
 3483     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/14")
 3484     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/15")
 3485     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/16")
 3486     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/17")
 3487     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/18")
 3488     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/19")
 3489     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/20")
 3490     # . epilogue
 3491     89/<- %esp 5/r32/ebp
 3492     5d/pop-to-ebp
 3493     c3/return
 3494 
 3495 test-convert-index-into-array-of-bytes:
 3496     # . prologue
 3497     55/push-ebp
 3498     89/<- %ebp 4/r32/esp
 3499     # setup
 3500     (clear-stream _test-input-stream)
 3501     (clear-stream $_test-input-buffered-file->buffer)
 3502     (clear-stream _test-output-stream)
 3503     (clear-stream $_test-output-buffered-file->buffer)
 3504     #
 3505     (write _test-input-stream "fn foo {\n")
 3506     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3507     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3508     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 3509     (write _test-input-stream "}\n")
 3510     # convert
 3511     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3512     (flush _test-output-buffered-file)
 3513 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3519     # check output
 3520     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 3521     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 3522     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 3523     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 3524     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 3525     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 3526     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 3527     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 3528     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 3529     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 3530     (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")
 3531     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 3532     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 3533     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 3534     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 3535     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 3536     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 3537     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 3538     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 3539     # . epilogue
 3540     89/<- %esp 5/r32/ebp
 3541     5d/pop-to-ebp
 3542     c3/return
 3543 
 3544 test-convert-index-into-array-with-literal:
 3545     # . prologue
 3546     55/push-ebp
 3547     89/<- %ebp 4/r32/esp
 3548     # setup
 3549     (clear-stream _test-input-stream)
 3550     (clear-stream $_test-input-buffered-file->buffer)
 3551     (clear-stream _test-output-stream)
 3552     (clear-stream $_test-output-buffered-file->buffer)
 3553     #
 3554     (write _test-input-stream "fn foo {\n")
 3555     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3556     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3557     (write _test-input-stream "}\n")
 3558     # convert
 3559     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3560     (flush _test-output-buffered-file)
 3561 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3567     # check output
 3568     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 3569     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 3570     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 3571     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 3572     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 3573     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 3574     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 3575     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 3576                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 3577     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 3578     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 3579     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 3580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 3581     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 3582     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 3583     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 3584     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 3585     # . epilogue
 3586     89/<- %esp 5/r32/ebp
 3587     5d/pop-to-ebp
 3588     c3/return
 3589 
 3590 test-convert-index-into-array-of-bytes-with-literal:
 3591     # . prologue
 3592     55/push-ebp
 3593     89/<- %ebp 4/r32/esp
 3594     # setup
 3595     (clear-stream _test-input-stream)
 3596     (clear-stream $_test-input-buffered-file->buffer)
 3597     (clear-stream _test-output-stream)
 3598     (clear-stream $_test-output-buffered-file->buffer)
 3599     #
 3600     (write _test-input-stream "fn foo {\n")
 3601     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3602     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 3603     (write _test-input-stream "}\n")
 3604     # convert
 3605     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3606     (flush _test-output-buffered-file)
 3607 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3613     # check output
 3614     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 3615     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 3616     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 3617     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 3618     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 3619     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 3620     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 3621     (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")
 3622                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 3623     (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")
 3624     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 3625     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 3626     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 3627     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 3628     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 3629     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 3630     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 3631     # . epilogue
 3632     89/<- %esp 5/r32/ebp
 3633     5d/pop-to-ebp
 3634     c3/return
 3635 
 3636 test-convert-index-into-array-on-stack:
 3637     # . prologue
 3638     55/push-ebp
 3639     89/<- %ebp 4/r32/esp
 3640     # setup
 3641     (clear-stream _test-input-stream)
 3642     (clear-stream $_test-input-buffered-file->buffer)
 3643     (clear-stream _test-output-stream)
 3644     (clear-stream $_test-output-buffered-file->buffer)
 3645     #
 3646     (write _test-input-stream "fn foo {\n")
 3647     (write _test-input-stream "  var arr: (array int 3)\n")
 3648     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 3649     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3650     (write _test-input-stream "}\n")
 3651     # convert
 3652     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3653     (flush _test-output-buffered-file)
 3654 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3660     # check output
 3661     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 3662     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 3663     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 3664     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 3665     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 3666     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 3667     # var arr
 3668     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 3669     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 3670     # var idx
 3671     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 3672     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 3673     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 3674     (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")
 3675     # reclaim idx
 3676     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 3677     # reclaim arr
 3678     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 3679     #
 3680     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 3681     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 3682     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 3683     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 3684     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 3685     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 3686     # . epilogue
 3687     89/<- %esp 5/r32/ebp
 3688     5d/pop-to-ebp
 3689     c3/return
 3690 
 3691 test-convert-index-into-array-on-stack-with-literal:
 3692     # . prologue
 3693     55/push-ebp
 3694     89/<- %ebp 4/r32/esp
 3695     # setup
 3696     (clear-stream _test-input-stream)
 3697     (clear-stream $_test-input-buffered-file->buffer)
 3698     (clear-stream _test-output-stream)
 3699     (clear-stream $_test-output-buffered-file->buffer)
 3700     #
 3701     (write _test-input-stream "fn foo {\n")
 3702     (write _test-input-stream "  var arr: (array int 3)\n")
 3703     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3704     (write _test-input-stream "}\n")
 3705     # convert
 3706     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3707     (flush _test-output-buffered-file)
 3708 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3714     # check output
 3715     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 3716     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 3717     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 3718     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 3719     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 3720     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 3721     # var arr
 3722     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 3723     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 3724     # var x
 3725     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 3726     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 3727     (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")
 3728     # reclaim x
 3729     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 3730     # reclaim arr
 3731     (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")
 3732     #
 3733     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 3734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 3735     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 3736     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 3737     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 3738     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 3739     # . epilogue
 3740     89/<- %esp 5/r32/ebp
 3741     5d/pop-to-ebp
 3742     c3/return
 3743 
 3744 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 3745     # . prologue
 3746     55/push-ebp
 3747     89/<- %ebp 4/r32/esp
 3748     # setup
 3749     (clear-stream _test-input-stream)
 3750     (clear-stream $_test-input-buffered-file->buffer)
 3751     (clear-stream _test-output-stream)
 3752     (clear-stream $_test-output-buffered-file->buffer)
 3753     #
 3754     (write _test-input-stream "fn foo {\n")
 3755     (write _test-input-stream "  var arr: (array byte 3)\n")
 3756     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 3757     (write _test-input-stream "}\n")
 3758     # convert
 3759     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3760     (flush _test-output-buffered-file)
 3761 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3767     # check output
 3768     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 3769     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 3770     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 3771     (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")
 3772     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 3773     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 3774     # var arr
 3775     (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")
 3776     (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")
 3777     # var x
 3778     (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")
 3779     # x is at (ebp-7) + 4 + 2 = ebp-1
 3780     (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")
 3781     # reclaim x
 3782     (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")
 3783     # reclaim arr
 3784     (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")
 3785     #
 3786     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 3787     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 3788     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 3789     (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")
 3790     (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")
 3791     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 3792     # . epilogue
 3793     89/<- %esp 5/r32/ebp
 3794     5d/pop-to-ebp
 3795     c3/return
 3796 
 3797 test-convert-index-into-array-using-offset:
 3798     # . prologue
 3799     55/push-ebp
 3800     89/<- %ebp 4/r32/esp
 3801     # setup
 3802     (clear-stream _test-input-stream)
 3803     (clear-stream $_test-input-buffered-file->buffer)
 3804     (clear-stream _test-output-stream)
 3805     (clear-stream $_test-output-buffered-file->buffer)
 3806     #
 3807     (write _test-input-stream "fn foo {\n")
 3808     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3809     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3810     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 3811     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 3812     (write _test-input-stream "}\n")
 3813     # convert
 3814     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3815     (flush _test-output-buffered-file)
 3816 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3822     # check output
 3823     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 3824     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 3825     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 3826     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 3827     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 3828     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 3829     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 3830     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 3831     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 3832     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 3833     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 3834     (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")
 3835     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 3836     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 3837     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 3838     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 3839     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 3840     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 3841     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 3842     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 3843     # . epilogue
 3844     89/<- %esp 5/r32/ebp
 3845     5d/pop-to-ebp
 3846     c3/return
 3847 
 3848 test-convert-index-into-array-of-bytes-using-offset:
 3849     # . prologue
 3850     55/push-ebp
 3851     89/<- %ebp 4/r32/esp
 3852     # setup
 3853     (clear-stream _test-input-stream)
 3854     (clear-stream $_test-input-buffered-file->buffer)
 3855     (clear-stream _test-output-stream)
 3856     (clear-stream $_test-output-buffered-file->buffer)
 3857     #
 3858     (write _test-input-stream "fn foo {\n")
 3859     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3860     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3861     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 3862     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 3863     (write _test-input-stream "}\n")
 3864     # convert
 3865     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3866     (flush _test-output-buffered-file)
 3867 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3873     # check output
 3874     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 3875     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 3876     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 3877     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 3878     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 3879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 3880     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 3881     (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")
 3882     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 3883     (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")
 3884     (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")
 3885     (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")
 3886     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 3887     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 3888     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 3889     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 3890     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 3891     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 3892     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 3893     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 3894     # . epilogue
 3895     89/<- %esp 5/r32/ebp
 3896     5d/pop-to-ebp
 3897     c3/return
 3898 
 3899 test-convert-index-into-array-using-offset-on-stack:
 3900     # . prologue
 3901     55/push-ebp
 3902     89/<- %ebp 4/r32/esp
 3903     # setup
 3904     (clear-stream _test-input-stream)
 3905     (clear-stream $_test-input-buffered-file->buffer)
 3906     (clear-stream _test-output-stream)
 3907     (clear-stream $_test-output-buffered-file->buffer)
 3908     #
 3909     (write _test-input-stream "fn foo {\n")
 3910     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3911     (write _test-input-stream "  var idx: int\n")
 3912     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 3913     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 3914     (write _test-input-stream "}\n")
 3915     # convert
 3916     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3917     (flush _test-output-buffered-file)
 3918 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3924     # check output
 3925     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 3926     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 3927     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 3928     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 3929     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 3930     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 3931     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 3932     (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")
 3933     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 3934     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 3935     (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")
 3936     (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")
 3937     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 3938     (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")
 3939     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 3940     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 3941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 3942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 3943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 3944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 3945     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 3946     # . epilogue
 3947     89/<- %esp 5/r32/ebp
 3948     5d/pop-to-ebp
 3949     c3/return
 3950 
 3951 test-convert-index-into-array-of-bytes-using-offset-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/eax: (addr array byte) <- copy 0\n")
 3963     (write _test-input-stream "  var idx: int\n")
 3964     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 3965     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 3966     (write _test-input-stream "}\n")
 3967     # convert
 3968     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3969     (flush _test-output-buffered-file)
 3970 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3976     # check output
 3977     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 3978     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 3979     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 3980     (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")
 3981     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 3982     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 3983     (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")
 3984     (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")
 3985     (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")
 3986     (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")
 3987     (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")
 3988     (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")
 3989     (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")
 3990     (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")
 3991     (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")
 3992     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 3993     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 3994     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 3995     (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")
 3996     (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")
 3997     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 3998     # . epilogue
 3999     89/<- %esp 5/r32/ebp
 4000     5d/pop-to-ebp
 4001     c3/return
 4002 
 4003 test-convert-function-and-type-definition:
 4004     # . prologue
 4005     55/push-ebp
 4006     89/<- %ebp 4/r32/esp
 4007     # setup
 4008     (clear-stream _test-input-stream)
 4009     (clear-stream $_test-input-buffered-file->buffer)
 4010     (clear-stream _test-output-stream)
 4011     (clear-stream $_test-output-buffered-file->buffer)
 4012     #
 4013     (write _test-input-stream "fn foo a: (addr t) {\n")
 4014     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4015     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4016     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4017     (write _test-input-stream "}\n")
 4018     (write _test-input-stream "type t {\n")
 4019     (write _test-input-stream "  x: int\n")
 4020     (write _test-input-stream "  y: int\n")
 4021     (write _test-input-stream "}\n")
 4022     # convert
 4023     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4024     (flush _test-output-buffered-file)
 4025 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4031     # check output
 4032     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4033     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4034     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4035     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4036     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4037     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4038     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4039     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4040     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4041     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4042     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4043     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4044     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4045     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4047     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4048     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4049     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4050     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4051     # . epilogue
 4052     89/<- %esp 5/r32/ebp
 4053     5d/pop-to-ebp
 4054     c3/return
 4055 
 4056 test-convert-function-with-local-var-with-user-defined-type:
 4057     # . prologue
 4058     55/push-ebp
 4059     89/<- %ebp 4/r32/esp
 4060     # setup
 4061     (clear-stream _test-input-stream)
 4062     (clear-stream $_test-input-buffered-file->buffer)
 4063     (clear-stream _test-output-stream)
 4064     (clear-stream $_test-output-buffered-file->buffer)
 4065     #
 4066     (write _test-input-stream "fn foo {\n")
 4067     (write _test-input-stream "  var a: t\n")
 4068     (write _test-input-stream "}\n")
 4069     (write _test-input-stream "type t {\n")
 4070     (write _test-input-stream "  x: int\n")
 4071     (write _test-input-stream "  y: int\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-function-with-local-var-with-user-defined-type/0")
 4084     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 4085     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 4086     (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")
 4087     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 4088     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 4089     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 4090     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 4091     (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")
 4092     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 4093     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 4094     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 4095     (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")
 4096     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 4097     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 4098     # . epilogue
 4099     89/<- %esp 5/r32/ebp
 4100     5d/pop-to-ebp
 4101     c3/return
 4102 
 4103 test-convert-function-call-with-arg-of-user-defined-type:
 4104     # . prologue
 4105     55/push-ebp
 4106     89/<- %ebp 4/r32/esp
 4107     # setup
 4108     (clear-stream _test-input-stream)
 4109     (clear-stream $_test-input-buffered-file->buffer)
 4110     (clear-stream _test-output-stream)
 4111     (clear-stream $_test-output-buffered-file->buffer)
 4112     #
 4113     (write _test-input-stream "fn f {\n")
 4114     (write _test-input-stream "  var a: t\n")
 4115     (write _test-input-stream "  foo a\n")
 4116     (write _test-input-stream "}\n")
 4117     (write _test-input-stream "fn foo x: t {\n")
 4118     (write _test-input-stream "}\n")
 4119     (write _test-input-stream "type t {\n")
 4120     (write _test-input-stream "  x: int\n")
 4121     (write _test-input-stream "  y: int\n")
 4122     (write _test-input-stream "}\n")
 4123     # convert
 4124     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4125     (flush _test-output-buffered-file)
 4126 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4132     # check output
 4133     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4134     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4135     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4136     (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")
 4137     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4138     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4139     # var a: t
 4140     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 4141     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 4142     # foo a
 4143     (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")
 4144     #
 4145     (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")
 4146     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4147     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4148     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4149     (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")
 4150     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4151     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4152     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4153     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4154     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4155     (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")
 4156     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4157     (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")
 4158     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4159     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4160     # . epilogue
 4161     89/<- %esp 5/r32/ebp
 4162     5d/pop-to-ebp
 4163     c3/return
 4164 
 4165 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 4166     # . prologue
 4167     55/push-ebp
 4168     89/<- %ebp 4/r32/esp
 4169     # setup
 4170     (clear-stream _test-input-stream)
 4171     (clear-stream $_test-input-buffered-file->buffer)
 4172     (clear-stream _test-output-stream)
 4173     (clear-stream $_test-output-buffered-file->buffer)
 4174     #
 4175     (write _test-input-stream "fn f {\n")
 4176     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 4177     (write _test-input-stream "  foo *a\n")
 4178     (write _test-input-stream "}\n")
 4179     (write _test-input-stream "fn foo x: t {\n")
 4180     (write _test-input-stream "}\n")
 4181     (write _test-input-stream "type t {\n")
 4182     (write _test-input-stream "  x: int\n")
 4183     (write _test-input-stream "  y: int\n")
 4184     (write _test-input-stream "}\n")
 4185     # convert
 4186     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4187     (flush _test-output-buffered-file)
 4188 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4194     # check output
 4195     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4196     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4197     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4198     (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")
 4199     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4200     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4201     # var a
 4202     (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")
 4203     (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")
 4204     # foo a
 4205     (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")
 4206     #
 4207     (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")
 4208     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4209     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4210     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4211     (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")
 4212     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4213     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4214     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4215     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4216     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4217     (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")
 4218     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4219     (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")
 4220     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4221     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4222     # . epilogue
 4223     89/<- %esp 5/r32/ebp
 4224     5d/pop-to-ebp
 4225     c3/return
 4226 
 4227 # we don't have special support for call-by-reference; just explicitly create
 4228 # a new variable with the address of the arg
 4229 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 4230     # . prologue
 4231     55/push-ebp
 4232     89/<- %ebp 4/r32/esp
 4233     # setup
 4234     (clear-stream _test-input-stream)
 4235     (clear-stream $_test-input-buffered-file->buffer)
 4236     (clear-stream _test-output-stream)
 4237     (clear-stream $_test-output-buffered-file->buffer)
 4238     #
 4239     (write _test-input-stream "fn f {\n")
 4240     (write _test-input-stream "  var a: t\n")
 4241     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 4242     (write _test-input-stream "  foo b\n")
 4243     (write _test-input-stream "}\n")
 4244     (write _test-input-stream "fn foo x: (addr t) {\n")
 4245     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 4246     (write _test-input-stream "  increment *x\n")
 4247     (write _test-input-stream "}\n")
 4248     (write _test-input-stream "type t {\n")
 4249     (write _test-input-stream "  x: int\n")
 4250     (write _test-input-stream "  y: int\n")
 4251     (write _test-input-stream "}\n")
 4252     # convert
 4253     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4254     (flush _test-output-buffered-file)
 4255 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4261     # check output
 4262     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 4263     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 4264     (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")
 4265     (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")
 4266     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 4267     (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")
 4268     # var a: t
 4269     (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")
 4270     (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")
 4271     # var b/eax: (addr t)
 4272     (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")
 4273     (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")
 4274     # foo a
 4275     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 4276     #
 4277     (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")
 4278     (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")
 4279     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 4280     (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")
 4281     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 4282     (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")
 4283     (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")
 4284     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 4285     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 4286     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 4287     (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")
 4288     (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")
 4289     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 4290     (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")
 4291     (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")
 4292     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26")
 4293     (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")
 4294     (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")
 4295     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 4296     (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")
 4297     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 4298     (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")
 4299     (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")
 4300     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 4301     # . epilogue
 4302     89/<- %esp 5/r32/ebp
 4303     5d/pop-to-ebp
 4304     c3/return
 4305 
 4306 test-convert-get-on-local-variable:
 4307     # . prologue
 4308     55/push-ebp
 4309     89/<- %ebp 4/r32/esp
 4310     # setup
 4311     (clear-stream _test-input-stream)
 4312     (clear-stream $_test-input-buffered-file->buffer)
 4313     (clear-stream _test-output-stream)
 4314     (clear-stream $_test-output-buffered-file->buffer)
 4315     #
 4316     (write _test-input-stream "fn foo {\n")
 4317     (write _test-input-stream "  var a: t\n")
 4318     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4319     (write _test-input-stream "}\n")
 4320     (write _test-input-stream "type t {\n")
 4321     (write _test-input-stream "  x: int\n")
 4322     (write _test-input-stream "  y: int\n")
 4323     (write _test-input-stream "}\n")
 4324     # convert
 4325     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4326     (flush _test-output-buffered-file)
 4327 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4333     # check output
 4334     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 4335     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 4336     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 4337     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 4338     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 4339     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 4340     # var a
 4341     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 4342     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 4343     # var c
 4344     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 4345     # get
 4346     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 4347     # reclaim c
 4348     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 4349     # reclaim a
 4350     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 4351     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 4352     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 4353     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 4354     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 4355     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 4356     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 4357     # . epilogue
 4358     89/<- %esp 5/r32/ebp
 4359     5d/pop-to-ebp
 4360     c3/return
 4361 
 4362 test-convert-get-on-function-argument:
 4363     # . prologue
 4364     55/push-ebp
 4365     89/<- %ebp 4/r32/esp
 4366     # setup
 4367     (clear-stream _test-input-stream)
 4368     (clear-stream $_test-input-buffered-file->buffer)
 4369     (clear-stream _test-output-stream)
 4370     (clear-stream $_test-output-buffered-file->buffer)
 4371     #
 4372     (write _test-input-stream "fn foo a: t {\n")
 4373     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4374     (write _test-input-stream "}\n")
 4375     (write _test-input-stream "type t {\n")
 4376     (write _test-input-stream "  x: int\n")
 4377     (write _test-input-stream "  y: int\n")
 4378     (write _test-input-stream "}\n")
 4379     # convert
 4380     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4381     (flush _test-output-buffered-file)
 4382 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4388     # check output
 4389     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 4390     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 4391     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 4392     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 4393     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 4394     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 4395     # var c
 4396     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 4397     # get
 4398     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 4399     # reclaim c
 4400     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 4401     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 4402     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 4403     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 4404     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 4405     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 4406     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 4407     # . epilogue
 4408     89/<- %esp 5/r32/ebp
 4409     5d/pop-to-ebp
 4410     c3/return
 4411 
 4412 test-convert-get-on-function-argument-with-known-type:
 4413     # . prologue
 4414     55/push-ebp
 4415     89/<- %ebp 4/r32/esp
 4416     # setup
 4417     (clear-stream _test-input-stream)
 4418     (clear-stream $_test-input-buffered-file->buffer)
 4419     (clear-stream _test-output-stream)
 4420     (clear-stream $_test-output-buffered-file->buffer)
 4421     #
 4422     (write _test-input-stream "type t {\n")
 4423     (write _test-input-stream "  x: int\n")
 4424     (write _test-input-stream "  y: int\n")
 4425     (write _test-input-stream "}\n")
 4426     (write _test-input-stream "fn foo a: t {\n")
 4427     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4428     (write _test-input-stream "}\n")
 4429     # convert
 4430     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4431     (flush _test-output-buffered-file)
 4432 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4438     # check output
 4439     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 4440     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 4441     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 4442     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 4443     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 4444     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 4445     # var c
 4446     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 4447     # get
 4448     (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")
 4449     # reclaim c
 4450     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 4451     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 4452     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 4453     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 4454     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 4455     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 4456     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 4457     # . epilogue
 4458     89/<- %esp 5/r32/ebp
 4459     5d/pop-to-ebp
 4460     c3/return
 4461 
 4462 test-get-with-wrong-field:
 4463     # . prologue
 4464     55/push-ebp
 4465     89/<- %ebp 4/r32/esp
 4466     # setup
 4467     (clear-stream _test-input-stream)
 4468     (clear-stream $_test-input-buffered-file->buffer)
 4469     (clear-stream _test-output-stream)
 4470     (clear-stream $_test-output-buffered-file->buffer)
 4471     (clear-stream _test-error-stream)
 4472     (clear-stream $_test-error-buffered-file->buffer)
 4473     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4474     68/push 0/imm32
 4475     68/push 0/imm32
 4476     89/<- %edx 4/r32/esp
 4477     (tailor-exit-descriptor %edx 0x10)
 4478     #
 4479     (write _test-input-stream "fn foo {\n")
 4480     (write _test-input-stream "  var a: t\n")
 4481     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4482     (write _test-input-stream "}\n")
 4483     (write _test-input-stream "type t {\n")
 4484     (write _test-input-stream "  x: int\n")
 4485     (write _test-input-stream "}\n")
 4486     # convert
 4487     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4488     # registers except esp clobbered at this point
 4489     # restore ed
 4490     89/<- %edx 4/r32/esp
 4491     (flush _test-output-buffered-file)
 4492     (flush _test-error-buffered-file)
 4493 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4499     # check output
 4500     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 4501     (check-next-stream-line-equal _test-error-stream  "type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
 4502     # check that stop(1) was called
 4503     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 4504     # don't restore from ebp
 4505     81 0/subop/add %esp 8/imm32
 4506     # . epilogue
 4507     5d/pop-to-ebp
 4508     c3/return
 4509 
 4510 test-convert-array-of-user-defined-types:
 4511     # . prologue
 4512     55/push-ebp
 4513     89/<- %ebp 4/r32/esp
 4514     # setup
 4515     (clear-stream _test-input-stream)
 4516     (clear-stream $_test-input-buffered-file->buffer)
 4517     (clear-stream _test-output-stream)
 4518     (clear-stream $_test-output-buffered-file->buffer)
 4519     #
 4520     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 4521     (write _test-input-stream "  x: int\n")
 4522     (write _test-input-stream "  y: int\n")
 4523     (write _test-input-stream "}\n")
 4524     (write _test-input-stream "fn foo {\n")
 4525     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4526     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4527     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4528     (write _test-input-stream "}\n")
 4529     # convert
 4530     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4531     (flush _test-output-buffered-file)
 4532 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4538     # check output
 4539     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 4540     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 4541     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 4542     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 4543     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 4544     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 4545     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 4546     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 4547     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 4548     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 4549     (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")
 4550     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 4551     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 4552     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 4553     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 4554     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 4555     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 4556     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 4557     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 4558     # . epilogue
 4559     89/<- %esp 5/r32/ebp
 4560     5d/pop-to-ebp
 4561     c3/return
 4562 
 4563 test-convert-length-of-array-of-user-defined-types-to-eax:
 4564     # . prologue
 4565     55/push-ebp
 4566     89/<- %ebp 4/r32/esp
 4567     # setup
 4568     (clear-stream _test-input-stream)
 4569     (clear-stream $_test-input-buffered-file->buffer)
 4570     (clear-stream _test-output-stream)
 4571     (clear-stream $_test-output-buffered-file->buffer)
 4572     #
 4573     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 4574     (write _test-input-stream "  x: int\n")
 4575     (write _test-input-stream "  y: int\n")
 4576     (write _test-input-stream "  z: int\n")
 4577     (write _test-input-stream "}\n")
 4578     (write _test-input-stream "fn foo {\n")
 4579     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4580     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 4581     (write _test-input-stream "}\n")
 4582     # convert
 4583     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4584     (flush _test-output-buffered-file)
 4585 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4591     # check output
 4592     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 4593     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 4594     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 4595     (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")
 4596     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 4597     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 4598     # var arr
 4599     (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")
 4600     (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")
 4601     # length instruction
 4602     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 4603     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 4604     (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")
 4605     (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")
 4606     (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")
 4607     (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")
 4608     (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")
 4609     (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")
 4610     # reclaim arr
 4611     (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")
 4612     #
 4613     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 4614     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 4615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 4616     (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")
 4617     (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")
 4618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 4619     # . epilogue
 4620     89/<- %esp 5/r32/ebp
 4621     5d/pop-to-ebp
 4622     c3/return
 4623 
 4624 test-convert-length-of-array-of-user-defined-types-to-ecx:
 4625     # . prologue
 4626     55/push-ebp
 4627     89/<- %ebp 4/r32/esp
 4628     # setup
 4629     (clear-stream _test-input-stream)
 4630     (clear-stream $_test-input-buffered-file->buffer)
 4631     (clear-stream _test-output-stream)
 4632     (clear-stream $_test-output-buffered-file->buffer)
 4633     #
 4634     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 4635     (write _test-input-stream "  x: int\n")
 4636     (write _test-input-stream "  y: int\n")
 4637     (write _test-input-stream "  z: int\n")
 4638     (write _test-input-stream "}\n")
 4639     (write _test-input-stream "fn foo {\n")
 4640     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4641     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 4642     (write _test-input-stream "}\n")
 4643     # convert
 4644     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4645     (flush _test-output-buffered-file)
 4646 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4652     # check output
 4653     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 4654     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 4655     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 4656     (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")
 4657     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 4658     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 4659     # var a
 4660     (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")
 4661     (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")
 4662     # var x
 4663     (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")
 4664     # length instruction
 4665     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 4666     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 4667     (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")
 4668     (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")
 4669     (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")
 4670     (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")
 4671     (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")
 4672     (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")
 4673     (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")
 4674     # reclaim x
 4675     (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")
 4676     # reclaim a
 4677     (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")
 4678     #
 4679     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 4680     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 4681     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 4682     (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")
 4683     (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")
 4684     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 4685     # . epilogue
 4686     89/<- %esp 5/r32/ebp
 4687     5d/pop-to-ebp
 4688     c3/return
 4689 
 4690 test-convert-length-of-array-of-user-defined-types-to-edx:
 4691     # . prologue
 4692     55/push-ebp
 4693     89/<- %ebp 4/r32/esp
 4694     # setup
 4695     (clear-stream _test-input-stream)
 4696     (clear-stream $_test-input-buffered-file->buffer)
 4697     (clear-stream _test-output-stream)
 4698     (clear-stream $_test-output-buffered-file->buffer)
 4699     #
 4700     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 4701     (write _test-input-stream "  x: int\n")
 4702     (write _test-input-stream "  y: int\n")
 4703     (write _test-input-stream "  z: int\n")
 4704     (write _test-input-stream "}\n")
 4705     (write _test-input-stream "fn foo {\n")
 4706     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4707     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 4708     (write _test-input-stream "}\n")
 4709     # convert
 4710     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4711     (flush _test-output-buffered-file)
 4712 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4718     # check output
 4719     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 4720     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 4721     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 4722     (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")
 4723     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 4724     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 4725     # var a
 4726     (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")
 4727     (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")
 4728     # var x
 4729     (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")
 4730     # length instruction
 4731     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 4732     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 4733     (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")
 4734     (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")
 4735     (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")
 4736     (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")
 4737     (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")
 4738     (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")
 4739     (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")
 4740     # reclaim x
 4741     (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")
 4742     # reclaim a
 4743     (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")
 4744     #
 4745     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 4746     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 4747     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 4748     (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")
 4749     (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")
 4750     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 4751     # . epilogue
 4752     89/<- %esp 5/r32/ebp
 4753     5d/pop-to-ebp
 4754     c3/return
 4755 
 4756 test-convert-length-of-array-of-user-defined-types:
 4757     # . prologue
 4758     55/push-ebp
 4759     89/<- %ebp 4/r32/esp
 4760     # setup
 4761     (clear-stream _test-input-stream)
 4762     (clear-stream $_test-input-buffered-file->buffer)
 4763     (clear-stream _test-output-stream)
 4764     (clear-stream $_test-output-buffered-file->buffer)
 4765     #
 4766     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 4767     (write _test-input-stream "  x: int\n")
 4768     (write _test-input-stream "  y: int\n")
 4769     (write _test-input-stream "  z: int\n")
 4770     (write _test-input-stream "}\n")
 4771     (write _test-input-stream "fn foo {\n")
 4772     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 4773     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 4774     (write _test-input-stream "}\n")
 4775     # convert
 4776     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4777     (flush _test-output-buffered-file)
 4778 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4784     # check output
 4785     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 4786     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 4787     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 4788     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 4789     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 4790     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 4791     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 4792     (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")
 4793     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 4794     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 4795     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 4796     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 4797     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 4798     (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")
 4799     (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")
 4800     (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")
 4801     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 4802     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 4803     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 4804     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 4805     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 4806     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 4807     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 4808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 4809     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 4810     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 4811     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 4812     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 4813     # . epilogue
 4814     89/<- %esp 5/r32/ebp
 4815     5d/pop-to-ebp
 4816     c3/return
 4817 
 4818 #######################################################
 4819 # Parsing
 4820 #######################################################
 4821 
 4822 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 4823     # pseudocode
 4824     #   var curr-function: (addr handle function) = Program->functions
 4825     #   var curr-type: (addr handle typeinfo) = Program->types
 4826     #   var line: (stream byte 512)
 4827     #   var word-slice: slice
 4828     #   while true                                  # line loop
 4829     #     clear-stream(line)
 4830     #     read-line-buffered(in, line)
 4831     #     if (line->write == 0) break               # end of file
 4832     #     word-slice = next-mu-token(line)
 4833     #     if slice-empty?(word-slice)               # end of line
 4834     #       continue
 4835     #     else if slice-starts-with?(word-slice, "#")  # comment
 4836     #       continue                                # end of line
 4837     #     else if slice-equal?(word-slice, "fn")
 4838     #       var new-function: (handle function) = allocate(function)
 4839     #       var vars: (stack live-var 256)
 4840     #       populate-mu-function-header(line, new-function, vars)
 4841     #       populate-mu-function-body(in, new-function, vars)
 4842     #       assert(vars->top == 0)
 4843     #       *curr-function = new-function
 4844     #       curr-function = &new-function->next
 4845     #     else if slice-equal?(word-slice, "type")
 4846     #       word-slice = next-mu-token(line)
 4847     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 4848     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 4849     #       assert(next-word(line) == "{")
 4850     #       populate-mu-type(in, new-type)
 4851     #     else
 4852     #       abort()
 4853     #
 4854     # . prologue
 4855     55/push-ebp
 4856     89/<- %ebp 4/r32/esp
 4857     # . save registers
 4858     50/push-eax
 4859     51/push-ecx
 4860     52/push-edx
 4861     53/push-ebx
 4862     56/push-esi
 4863     57/push-edi
 4864     # var line/ecx: (stream byte 512)
 4865     81 5/subop/subtract %esp 0x200/imm32
 4866     68/push 0x200/imm32/size
 4867     68/push 0/imm32/read
 4868     68/push 0/imm32/write
 4869     89/<- %ecx 4/r32/esp
 4870     # var word-slice/edx: slice
 4871     68/push 0/imm32/end
 4872     68/push 0/imm32/start
 4873     89/<- %edx 4/r32/esp
 4874     # var curr-function/edi: (addr handle function)
 4875     bf/copy-to-edi _Program-functions/imm32
 4876     # var vars/ebx: (stack live-var 256)
 4877     81 5/subop/subtract %esp 0xc00/imm32
 4878     68/push 0xc00/imm32/size
 4879     68/push 0/imm32/top
 4880     89/<- %ebx 4/r32/esp
 4881     {
 4882 $parse-mu:line-loop:
 4883       (clear-stream %ecx)
 4884       (read-line-buffered *(ebp+8) %ecx)
 4885       # if (line->write == 0) break
 4886       81 7/subop/compare *ecx 0/imm32
 4887       0f 84/jump-if-= break/disp32
 4888 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 4894       (next-mu-token %ecx %edx)
 4895       # if slice-empty?(word-slice) continue
 4896       (slice-empty? %edx)  # => eax
 4897       3d/compare-eax-and 0/imm32/false
 4898       0f 85/jump-if-!= loop/disp32
 4899       # if (*word-slice->start == "#") continue
 4900       # . eax = *word-slice->start
 4901       8b/-> *edx 0/r32/eax
 4902       8a/copy-byte *eax 0/r32/AL
 4903       81 4/subop/and %eax 0xff/imm32
 4904       # . if (eax == '#') continue
 4905       3d/compare-eax-and 0x23/imm32/hash
 4906       0f 84/jump-if-= loop/disp32
 4907       # if (slice-equal?(word-slice, "fn")) parse a function
 4908       {
 4909 $parse-mu:fn:
 4910         (slice-equal? %edx "fn")  # => eax
 4911         3d/compare-eax-and 0/imm32/false
 4912         0f 84/jump-if-= break/disp32
 4913         # var new-function/esi: (handle function)
 4914         68/push 0/imm32
 4915         68/push 0/imm32
 4916         89/<- %esi 4/r32/esp
 4917         # populate-mu-function(line, in, vars, new-function)
 4918         (allocate Heap *Function-size %esi)
 4919         # var new-function-addr/eax: (addr function)
 4920         (lookup *esi *(esi+4))  # => eax
 4921         (clear-stack %ebx)
 4922         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 4923         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 4924         # *curr-function = new-function
 4925         8b/-> *esi 0/r32/eax
 4926         89/<- *edi 0/r32/eax
 4927         8b/-> *(esi+4) 0/r32/eax
 4928         89/<- *(edi+4) 0/r32/eax
 4929         # curr-function = &new-function->next
 4930         # . var tmp/eax: (addr function) = lookup(new-function)
 4931         (lookup *esi *(esi+4))  # => eax
 4932         # . curr-function = &tmp->next
 4933         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 4934         # reclaim new-function
 4935         81 0/subop/add %esp 8/imm32
 4936         #
 4937         e9/jump $parse-mu:line-loop/disp32
 4938       }
 4939       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 4940       {
 4941 $parse-mu:type:
 4942         (slice-equal? %edx "type")  # => eax
 4943         3d/compare-eax-and 0/imm32
 4944         0f 84/jump-if-= break/disp32
 4945         (next-mu-token %ecx %edx)
 4946         # var type-id/eax: int
 4947         (pos-or-insert-slice Type-id %edx)  # => eax
 4948         # spill
 4949         51/push-ecx
 4950         # var new-type/ecx: (handle typeinfo)
 4951         68/push 0/imm32
 4952         68/push 0/imm32
 4953         89/<- %ecx 4/r32/esp
 4954         (find-or-create-typeinfo %eax %ecx)
 4955         #
 4956         (lookup *ecx *(ecx+4))  # => eax
 4957         # TODO: ensure that 'line' has nothing else but '{'
 4958 #? (dump-typeinfos "=== aaa\n")
 4959         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 4960 #? (dump-typeinfos "=== zzz\n")
 4961         # reclaim new-type
 4962         81 0/subop/add %esp 8/imm32
 4963         # restore
 4964         59/pop-to-ecx
 4965         e9/jump $parse-mu:line-loop/disp32
 4966       }
 4967       # otherwise abort
 4968       e9/jump $parse-mu:error1/disp32
 4969     } # end line loop
 4970 $parse-mu:end:
 4971     # . reclaim locals
 4972     81 0/subop/add %esp 0xe1c/imm32
 4973     # . restore registers
 4974     5f/pop-to-edi
 4975     5e/pop-to-esi
 4976     5b/pop-to-ebx
 4977     5a/pop-to-edx
 4978     59/pop-to-ecx
 4979     58/pop-to-eax
 4980     # . epilogue
 4981     89/<- %esp 5/r32/ebp
 4982     5d/pop-to-ebp
 4983     c3/return
 4984 
 4985 $parse-mu:error1:
 4986     # error("unexpected top-level command: " word-slice "\n")
 4987     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 4988     (write-slice-buffered *(ebp+0xc) %edx)
 4989     (write-buffered *(ebp+0xc) "\n")
 4990     (flush *(ebp+0xc))
 4991     (stop *(ebp+0x10) 1)
 4992     # never gets here
 4993 
 4994 $parse-mu:error2:
 4995     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 4996     (print-int32-buffered *(ebp+0xc) *ebx)
 4997     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 4998     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 4999     (write-buffered *(ebp+0xc) "'\n")
 5000     (flush *(ebp+0xc))
 5001     (stop *(ebp+0x10) 1)
 5002     # never gets here
 5003 
 5004 # scenarios considered:
 5005 # ✗ fn foo  # no block
 5006 # ✓ fn foo {
 5007 # ✗ fn foo { {
 5008 # ✗ fn foo { }
 5009 # ✗ fn foo { } {
 5010 # ✗ fn foo x {
 5011 # ✗ fn foo x: {
 5012 # ✓ fn foo x: int {
 5013 # ✓ fn foo x: int {
 5014 # ✓ fn foo x: int -> y/eax: int {
 5015 # TODO:
 5016 #   disallow outputs of type `(... addr ...)`
 5017 #   disallow inputs of type `(... addr ... addr ...)`
 5018 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)
 5019     # pseudocode:
 5020     #   var name: slice
 5021     #   next-mu-token(first-line, name)
 5022     #   assert(name not in '{' '}' '->')
 5023     #   out->name = slice-to-string(name)
 5024     #   ## inouts
 5025     #   while true
 5026     #     ## name
 5027     #     name = next-mu-token(first-line)
 5028     #     if (name == '{') goto done
 5029     #     if (name == '->') break
 5030     #     assert(name != '}')
 5031     #     var v: (handle var) = parse-var-with-type(name, first-line)
 5032     #     assert(v->register == null)
 5033     #     # v->block-depth is implicitly 0
 5034     #     out->inouts = append(v, out->inouts)
 5035     #     push(vars, {v, false})
 5036     #   ## outputs
 5037     #   while true
 5038     #     ## name
 5039     #     name = next-mu-token(first-line)
 5040     #     assert(name not in '{' '}' '->')
 5041     #     var v: (handle var) = parse-var-with-type(name, first-line)
 5042     #     assert(v->register != null)
 5043     #     out->outputs = append(v, out->outputs)
 5044     #   done:
 5045     #
 5046     # . prologue
 5047     55/push-ebp
 5048     89/<- %ebp 4/r32/esp
 5049     # . save registers
 5050     50/push-eax
 5051     51/push-ecx
 5052     52/push-edx
 5053     53/push-ebx
 5054     57/push-edi
 5055     # edi = out
 5056     8b/-> *(ebp+0xc) 7/r32/edi
 5057     # var word-slice/ecx: slice
 5058     68/push 0/imm32/end
 5059     68/push 0/imm32/start
 5060     89/<- %ecx 4/r32/esp
 5061     # var v/ebx: (handle var)
 5062     68/push 0/imm32
 5063     68/push 0/imm32
 5064     89/<- %ebx 4/r32/esp
 5065     # read function name
 5066     (next-mu-token *(ebp+8) %ecx)
 5067     # error checking
 5068     # TODO: error if name starts with 'break' or 'loop'
 5069     # if (word-slice == '{') abort
 5070     (slice-equal? %ecx "{")   # => eax
 5071     3d/compare-eax-and 0/imm32/false
 5072     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5073     # if (word-slice == '->') abort
 5074     (slice-equal? %ecx "->")   # => eax
 5075     3d/compare-eax-and 0/imm32/false
 5076     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5077     # if (word-slice == '}') abort
 5078     (slice-equal? %ecx "}")   # => eax
 5079     3d/compare-eax-and 0/imm32/false
 5080     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5081     # save function name
 5082     (slice-to-string Heap %ecx %edi)  # Function-name
 5083     # save function inouts
 5084     {
 5085 $populate-mu-function-header:check-for-inout:
 5086       (next-mu-token *(ebp+8) %ecx)
 5087       # if (word-slice == '{') goto done
 5088       (slice-equal? %ecx "{")   # => eax
 5089       3d/compare-eax-and 0/imm32/false
 5090       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 5091       # if (word-slice == '->') break
 5092       (slice-equal? %ecx "->")   # => eax
 5093       3d/compare-eax-and 0/imm32/false
 5094       0f 85/jump-if-!= break/disp32
 5095       # if (word-slice == '}') abort
 5096       (slice-equal? %ecx "}")   # => eax
 5097       3d/compare-eax-and 0/imm32/false
 5098       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5099       # v = parse-var-with-type(word-slice, first-line)
 5100       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 5101       # assert(v->register == null)
 5102       # . eax: (addr var) = lookup(v)
 5103       (lookup *ebx *(ebx+4))  # => eax
 5104       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 5105       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 5106       # v->block-depth is implicitly 0
 5107       #
 5108       # out->inouts = append(v, out->inouts)
 5109       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 5110       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 5111       # push(vars, {v, false})
 5112       (push *(ebp+0x10) *ebx)
 5113       (push *(ebp+0x10) *(ebx+4))
 5114       (push *(ebp+0x10) 0)  # false
 5115       #
 5116       e9/jump loop/disp32
 5117     }
 5118     # save function outputs
 5119     {
 5120 $populate-mu-function-header:check-for-out:
 5121       (next-mu-token *(ebp+8) %ecx)
 5122       # if (word-slice == '{') break
 5123       (slice-equal? %ecx "{")   # => eax
 5124       3d/compare-eax-and 0/imm32/false
 5125       0f 85/jump-if-!= break/disp32
 5126       # if (word-slice == '->') abort
 5127       (slice-equal? %ecx "->")   # => eax
 5128       3d/compare-eax-and 0/imm32/false
 5129       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5130       # if (word-slice == '}') abort
 5131       (slice-equal? %ecx "}")   # => eax
 5132       3d/compare-eax-and 0/imm32/false
 5133       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 5134       # v = parse-var-with-type(word-slice, first-line)
 5135       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 5136       # assert(var->register != null)
 5137       # . eax: (addr var) = lookup(v)
 5138       (lookup *ebx *(ebx+4))  # => eax
 5139       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 5140       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 5141       # out->outputs = append(v, out->outputs)
 5142       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 5143       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 5144       #
 5145       e9/jump loop/disp32
 5146     }
 5147 $populate-mu-function-header:done:
 5148     (check-no-tokens-left *(ebp+8))
 5149 $populate-mu-function-header:end:
 5150     # . reclaim locals
 5151     81 0/subop/add %esp 0x10/imm32
 5152     # . restore registers
 5153     5f/pop-to-edi
 5154     5b/pop-to-ebx
 5155     5a/pop-to-edx
 5156     59/pop-to-ecx
 5157     58/pop-to-eax
 5158     # . epilogue
 5159     89/<- %esp 5/r32/ebp
 5160     5d/pop-to-ebp
 5161     c3/return
 5162 
 5163 $populate-mu-function-header:error1:
 5164     # error("function header not in form 'fn <name> {'")
 5165     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 5166     (flush *(ebp+0x14))
 5167     (rewind-stream *(ebp+8))
 5168     (write-stream-data *(ebp+0x14) *(ebp+8))
 5169     (write-buffered *(ebp+0x14) "'\n")
 5170     (flush *(ebp+0x14))
 5171     (stop *(ebp+0x18) 1)
 5172     # never gets here
 5173 
 5174 $populate-mu-function-header:error2:
 5175     # error("function inout '" var "' cannot be in a register")
 5176     (write-buffered *(ebp+0x14) "function inout '")
 5177     (write-buffered *(ebp+0x14) *ebx)  # Var-name
 5178     (write-buffered *(ebp+0x14) "' cannot be in a register")
 5179     (flush *(ebp+0x14))
 5180     (stop *(ebp+0x18) 1)
 5181     # never gets here
 5182 
 5183 $populate-mu-function-header:error3:
 5184     # error("function output '" var "' must be in a register")
 5185     (write-buffered *(ebp+0x14) "function output '")
 5186     (lookup *ebx *(ebx+4))  # => eax
 5187     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 5188     (write-buffered *(ebp+0x14) %eax)
 5189     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 5190     (rewind-stream *(ebp+8))
 5191     (write-stream-data *(ebp+0x14) *(ebp+8))
 5192     (write-buffered *(ebp+0x14) "'\n")
 5193     (flush *(ebp+0x14))
 5194     (stop *(ebp+0x18) 1)
 5195     # never gets here
 5196 
 5197 test-function-header-with-arg:
 5198     # . prologue
 5199     55/push-ebp
 5200     89/<- %ebp 4/r32/esp
 5201     # setup
 5202     (clear-stream _test-input-stream)
 5203     (write _test-input-stream "foo n: int {\n")
 5204     # var result/ecx: function
 5205     2b/subtract *Function-size 4/r32/esp
 5206     89/<- %ecx 4/r32/esp
 5207     (zero-out %ecx *Function-size)
 5208     # var vars/ebx: (stack live-var 16)
 5209     81 5/subop/subtract %esp 0xc0/imm32
 5210     68/push 0xc0/imm32/size
 5211     68/push 0/imm32/top
 5212     89/<- %ebx 4/r32/esp
 5213     # convert
 5214     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5215     # check result->name
 5216     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5217     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 5218     # var v/edx: (addr var) = result->inouts->value
 5219     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5220     (lookup *eax *(eax+4))  # List-value List-value => eax
 5221     89/<- %edx 0/r32/eax
 5222     # check v->name
 5223     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5224     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 5225     # check v->type
 5226     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5227     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 5228     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 5229     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 5230     # . epilogue
 5231     89/<- %esp 5/r32/ebp
 5232     5d/pop-to-ebp
 5233     c3/return
 5234 
 5235 test-function-header-with-multiple-args:
 5236     # . prologue
 5237     55/push-ebp
 5238     89/<- %ebp 4/r32/esp
 5239     # setup
 5240     (clear-stream _test-input-stream)
 5241     (write _test-input-stream "foo a: int, b: int c: int {\n")
 5242     # result/ecx: function
 5243     2b/subtract *Function-size 4/r32/esp
 5244     89/<- %ecx 4/r32/esp
 5245     (zero-out %ecx *Function-size)
 5246     # var vars/ebx: (stack live-var 16)
 5247     81 5/subop/subtract %esp 0xc0/imm32
 5248     68/push 0xc0/imm32/size
 5249     68/push 0/imm32/top
 5250     89/<- %ebx 4/r32/esp
 5251     # convert
 5252     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5253     # check result->name
 5254     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5255     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 5256     # var inouts/edx: (addr list var) = lookup(result->inouts)
 5257     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5258     89/<- %edx 0/r32/eax
 5259 $test-function-header-with-multiple-args:inout0:
 5260     # var v/ebx: (addr var) = lookup(inouts->value)
 5261     (lookup *edx *(edx+4))  # List-value List-value => eax
 5262     89/<- %ebx 0/r32/eax
 5263     # check v->name
 5264     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5265     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 5266     # check v->type
 5267     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5268     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 5269     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 5270     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 5271 $test-function-header-with-multiple-args:inout1:
 5272     # inouts = lookup(inouts->next)
 5273     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5274     89/<- %edx 0/r32/eax
 5275     # v = lookup(inouts->value)
 5276     (lookup *edx *(edx+4))  # List-value List-value => eax
 5277     89/<- %ebx 0/r32/eax
 5278     # check v->name
 5279     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5280     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 5281     # check v->type
 5282     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5283     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 5284     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 5285     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 5286 $test-function-header-with-multiple-args:inout2:
 5287     # inouts = lookup(inouts->next)
 5288     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5289     89/<- %edx 0/r32/eax
 5290     # v = lookup(inouts->value)
 5291     (lookup *edx *(edx+4))  # List-value List-value => eax
 5292     89/<- %ebx 0/r32/eax
 5293     # check v->name
 5294     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5295     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 5296     # check v->type
 5297     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5298     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 5299     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 5300     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 5301     # . epilogue
 5302     89/<- %esp 5/r32/ebp
 5303     5d/pop-to-ebp
 5304     c3/return
 5305 
 5306 test-function-header-with-multiple-args-and-outputs:
 5307     # . prologue
 5308     55/push-ebp
 5309     89/<- %ebp 4/r32/esp
 5310     # setup
 5311     (clear-stream _test-input-stream)
 5312     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 5313     # result/ecx: function
 5314     2b/subtract *Function-size 4/r32/esp
 5315     89/<- %ecx 4/r32/esp
 5316     (zero-out %ecx *Function-size)
 5317     # var vars/ebx: (stack live-var 16)
 5318     81 5/subop/subtract %esp 0xc0/imm32
 5319     68/push 0xc0/imm32/size
 5320     68/push 0/imm32/top
 5321     89/<- %ebx 4/r32/esp
 5322     # convert
 5323     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 5324     # check result->name
 5325     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 5326     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 5327     # var inouts/edx: (addr list var) = lookup(result->inouts)
 5328     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 5329     89/<- %edx 0/r32/eax
 5330 $test-function-header-with-multiple-args-and-outputs:inout0:
 5331     # var v/ebx: (addr var) = lookup(inouts->value)
 5332     (lookup *edx *(edx+4))  # List-value List-value => eax
 5333     89/<- %ebx 0/r32/eax
 5334     # check v->name
 5335     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5336     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 5337     # check v->type
 5338     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5339     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 5340     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 5341     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 5342 $test-function-header-with-multiple-args-and-outputs:inout1:
 5343     # inouts = lookup(inouts->next)
 5344     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5345     89/<- %edx 0/r32/eax
 5346     # v = lookup(inouts->value)
 5347     (lookup *edx *(edx+4))  # List-value List-value => eax
 5348     89/<- %ebx 0/r32/eax
 5349     # check v->name
 5350     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5351     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 5352     # check v->type
 5353     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5354     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 5355     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 5356     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 5357 $test-function-header-with-multiple-args-and-outputs:inout2:
 5358     # inouts = lookup(inouts->next)
 5359     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5360     89/<- %edx 0/r32/eax
 5361     # v = lookup(inouts->value)
 5362     (lookup *edx *(edx+4))  # List-value List-value => eax
 5363     89/<- %ebx 0/r32/eax
 5364     # check v->name
 5365     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5366     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 5367     # check v->type
 5368     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5369     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 5370     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 5371     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 5372 $test-function-header-with-multiple-args-and-outputs:out0:
 5373     # var outputs/edx: (addr list var) = lookup(result->outputs)
 5374     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 5375     89/<- %edx 0/r32/eax
 5376     # v = lookup(outputs->value)
 5377     (lookup *edx *(edx+4))  # List-value List-value => eax
 5378     89/<- %ebx 0/r32/eax
 5379     # check v->name
 5380     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5381     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 5382     # check v->register
 5383     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 5384     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 5385     # check v->type
 5386     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5387     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 5388     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 5389     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 5390 $test-function-header-with-multiple-args-and-outputs:out1:
 5391     # outputs = lookup(outputs->next)
 5392     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 5393     89/<- %edx 0/r32/eax
 5394     # v = lookup(inouts->value)
 5395     (lookup *edx *(edx+4))  # List-value List-value => eax
 5396     89/<- %ebx 0/r32/eax
 5397     # check v->name
 5398     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 5399     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 5400     # check v->register
 5401     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 5402     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 5403     # check v->type
 5404     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 5405     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 5406     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 5407     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 5408     # . epilogue
 5409     89/<- %esp 5/r32/ebp
 5410     5d/pop-to-ebp
 5411     c3/return
 5412 
 5413 # format for variables with types
 5414 #   x: int
 5415 #   x: int,
 5416 #   x/eax: int
 5417 #   x/eax: int,
 5418 # ignores at most one trailing comma
 5419 # WARNING: modifies name
 5420 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 5421     # pseudocode:
 5422     #   var s: slice
 5423     #   if (!slice-ends-with(name, ":"))
 5424     #     abort
 5425     #   --name->end to skip ':'
 5426     #   next-token-from-slice(name->start, name->end, '/', s)
 5427     #   new-var-from-slice(s, out)
 5428     #   ## register
 5429     #   next-token-from-slice(s->end, name->end, '/', s)
 5430     #   if (!slice-empty?(s))
 5431     #     out->register = slice-to-string(s)
 5432     #   ## type
 5433     #   var type: (handle tree type-id) = parse-type(first-line)
 5434     #   out->type = type
 5435     #
 5436     # . prologue
 5437     55/push-ebp
 5438     89/<- %ebp 4/r32/esp
 5439     # . save registers
 5440     50/push-eax
 5441     51/push-ecx
 5442     52/push-edx
 5443     53/push-ebx
 5444     56/push-esi
 5445     57/push-edi
 5446     # esi = name
 5447     8b/-> *(ebp+8) 6/r32/esi
 5448     # if (!slice-ends-with?(name, ":")) abort
 5449     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 5450     49/decrement-ecx
 5451     8a/copy-byte *ecx 1/r32/CL
 5452     81 4/subop/and %ecx 0xff/imm32
 5453     81 7/subop/compare %ecx 0x3a/imm32/colon
 5454     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 5455     # --name->end to skip ':'
 5456     ff 1/subop/decrement *(esi+4)
 5457     # var s/ecx: slice
 5458     68/push 0/imm32/end
 5459     68/push 0/imm32/start
 5460     89/<- %ecx 4/r32/esp
 5461 $parse-var-with-type:parse-name:
 5462     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 5463 $parse-var-with-type:create-var:
 5464     # new-var-from-slice(s, out)
 5465     (new-var-from-slice Heap %ecx *(ebp+0x10))
 5466     # save out->register
 5467 $parse-var-with-type:save-register:
 5468     # . var out-addr/edi: (addr var) = lookup(*out)
 5469     8b/-> *(ebp+0x10) 7/r32/edi
 5470     (lookup *edi *(edi+4))  # => eax
 5471     89/<- %edi 0/r32/eax
 5472     # . s = next-token(...)
 5473     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 5474     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 5475     {
 5476 $parse-var-with-type:write-register:
 5477       (slice-empty? %ecx)  # => eax
 5478       3d/compare-eax-and 0/imm32/false
 5479       75/jump-if-!= break/disp8
 5480       # out->register = slice-to-string(s)
 5481       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 5482       (slice-to-string Heap %ecx %eax)
 5483     }
 5484 $parse-var-with-type:save-type:
 5485     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 5486     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5487 $parse-var-with-type:end:
 5488     # . reclaim locals
 5489     81 0/subop/add %esp 8/imm32
 5490     # . restore registers
 5491     5f/pop-to-edi
 5492     5e/pop-to-esi
 5493     5b/pop-to-ebx
 5494     5a/pop-to-edx
 5495     59/pop-to-ecx
 5496     58/pop-to-eax
 5497     # . epilogue
 5498     89/<- %esp 5/r32/ebp
 5499     5d/pop-to-ebp
 5500     c3/return
 5501 
 5502 $parse-var-with-type:abort:
 5503     # error("var should have form 'name: type' in '" line "'\n")
 5504     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 5505     (flush *(ebp+0x14))
 5506     (rewind-stream *(ebp+0xc))
 5507     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 5508     (write-buffered *(ebp+0x14) "'\n")
 5509     (flush *(ebp+0x14))
 5510     (stop *(ebp+0x18) 1)
 5511     # never gets here
 5512 
 5513 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 5514     # pseudocode:
 5515     #   var s: slice = next-mu-token(in)
 5516     #   assert s != ""
 5517     #   assert s != "->"
 5518     #   assert s != "{"
 5519     #   assert s != "}"
 5520     #   if s == ")"
 5521     #     return
 5522     #   out = allocate(Tree)
 5523     #   if s != "("
 5524     #     HACK: if s is an int, parse and return it
 5525     #     out->left-is-atom? = true
 5526     #     out->value = pos-or-insert-slice(Type-id, s)
 5527     #     return
 5528     #   out->left = parse-type(ad, in)
 5529     #   out->right = parse-type-tree(ad, in)
 5530     #
 5531     # . prologue
 5532     55/push-ebp
 5533     89/<- %ebp 4/r32/esp
 5534     # . save registers
 5535     50/push-eax
 5536     51/push-ecx
 5537     52/push-edx
 5538     # clear out
 5539     (zero-out *(ebp+0x10) *Handle-size)
 5540     # var s/ecx: slice
 5541     68/push 0/imm32
 5542     68/push 0/imm32
 5543     89/<- %ecx 4/r32/esp
 5544     # s = next-mu-token(in)
 5545     (next-mu-token *(ebp+0xc) %ecx)
 5546 #?     (write-buffered Stderr "tok: ")
 5547 #?     (write-slice-buffered Stderr %ecx)
 5548 #?     (write-buffered Stderr "$\n")
 5549 #?     (flush Stderr)
 5550     # assert s != ""
 5551     (slice-equal? %ecx "")  # => eax
 5552     3d/compare-eax-and 0/imm32/false
 5553     0f 85/jump-if-!= $parse-type:abort/disp32
 5554     # assert s != "{"
 5555     (slice-equal? %ecx "{")  # => eax
 5556     3d/compare-eax-and 0/imm32/false
 5557     0f 85/jump-if-!= $parse-type:abort/disp32
 5558     # assert s != "}"
 5559     (slice-equal? %ecx "}")  # => eax
 5560     3d/compare-eax-and 0/imm32/false
 5561     0f 85/jump-if-!= $parse-type:abort/disp32
 5562     # assert s != "->"
 5563     (slice-equal? %ecx "->")  # => eax
 5564     3d/compare-eax-and 0/imm32/false
 5565     0f 85/jump-if-!= $parse-type:abort/disp32
 5566     # if (s == ")") return
 5567     (slice-equal? %ecx ")")  # => eax
 5568     3d/compare-eax-and 0/imm32/false
 5569     0f 85/jump-if-!= $parse-type:end/disp32
 5570     # out = new tree
 5571     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 5572     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 5573     8b/-> *(ebp+0x10) 2/r32/edx
 5574     (lookup *edx *(edx+4))  # => eax
 5575     89/<- %edx 0/r32/eax
 5576     {
 5577       # if (s != "(") break
 5578       (slice-equal? %ecx "(")  # => eax
 5579       3d/compare-eax-and 0/imm32/false
 5580       75/jump-if-!= break/disp8
 5581       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 5582       {
 5583 $parse-type:check-for-int:
 5584         (is-hex-int? %ecx)  # => eax
 5585         3d/compare-eax-and 0/imm32/false
 5586         74/jump-if-= break/disp8
 5587 $parse-type:int:
 5588         (parse-hex-int-from-slice %ecx)  # => eax
 5589         89/<- *(edx+4) 0/r32/eax  # Tree-value
 5590         e9/jump $parse-type:end/disp32
 5591       }
 5592 $parse-type:atom:
 5593       # out->left-is-atom? = true
 5594       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 5595       # out->value = pos-or-insert-slice(Type-id, s)
 5596       (pos-or-insert-slice Type-id %ecx)  # => eax
 5597       89/<- *(edx+4) 0/r32/eax  # Tree-value
 5598       e9/jump $parse-type:end/disp32
 5599     }
 5600 $parse-type:non-atom:
 5601     # otherwise s == "("
 5602     # out->left = parse-type(ad, in)
 5603     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 5604     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5605     # out->right = parse-type-tree(ad, in)
 5606     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 5607     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5608 $parse-type:end:
 5609     # . reclaim locals
 5610     81 0/subop/add %esp 8/imm32
 5611     # . restore registers
 5612     5a/pop-to-edx
 5613     59/pop-to-ecx
 5614     58/pop-to-eax
 5615     # . epilogue
 5616     89/<- %esp 5/r32/ebp
 5617     5d/pop-to-ebp
 5618     c3/return
 5619 
 5620 $parse-type:abort:
 5621     # error("unexpected token when parsing type: '" s "'\n")
 5622     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 5623     (write-slice-buffered *(ebp+0x14) %ecx)
 5624     (write-buffered *(ebp+0x14) "'\n")
 5625     (flush *(ebp+0x14))
 5626     (stop *(ebp+0x18) 1)
 5627     # never gets here
 5628 
 5629 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)
 5630     # pseudocode:
 5631     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 5632     #   if tmp == 0
 5633     #     return 0
 5634     #   out = allocate(Tree)
 5635     #   out->left = tmp
 5636     #   out->right = parse-type-tree(ad, in)
 5637     #
 5638     # . prologue
 5639     55/push-ebp
 5640     89/<- %ebp 4/r32/esp
 5641     # . save registers
 5642     50/push-eax
 5643     51/push-ecx
 5644     52/push-edx
 5645     #
 5646     (zero-out *(ebp+0x10) *Handle-size)
 5647     # var tmp/ecx: (handle tree type-id)
 5648     68/push 0/imm32
 5649     68/push 0/imm32
 5650     89/<- %ecx 4/r32/esp
 5651     # tmp = parse-type(ad, in)
 5652     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 5653     # if (tmp == 0) return
 5654     81 7/subop/compare *ecx 0/imm32
 5655     74/jump-if-= $parse-type-tree:end/disp8
 5656     # out = new tree
 5657     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 5658     # var out-addr/edx: (addr tree) = lookup(*out)
 5659     8b/-> *(ebp+0x10) 2/r32/edx
 5660     (lookup *edx *(edx+4))  # => eax
 5661     89/<- %edx 0/r32/eax
 5662     # out->left = tmp
 5663     8b/-> *ecx 0/r32/eax
 5664     89/<- *(edx+4) 0/r32/eax  # Tree-left
 5665     8b/-> *(ecx+4) 0/r32/eax
 5666     89/<- *(edx+8) 0/r32/eax  # Tree-left
 5667     # out->right = parse-type-tree(ad, in)
 5668     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 5669     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 5670 $parse-type-tree:end:
 5671     # . reclaim locals
 5672     81 0/subop/add %esp 8/imm32
 5673     # . restore registers
 5674     5a/pop-to-edx
 5675     59/pop-to-ecx
 5676     58/pop-to-eax
 5677     # . epilogue
 5678     89/<- %esp 5/r32/ebp
 5679     5d/pop-to-ebp
 5680     c3/return
 5681 
 5682 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 5683     # pseudocode:
 5684     # start:
 5685     #   skip-chars-matching-whitespace(in)
 5686     #   if in->read >= in->write              # end of in
 5687     #     out = {0, 0}
 5688     #     return
 5689     #   out->start = &in->data[in->read]
 5690     #   var curr-byte/eax: byte = in->data[in->read]
 5691     #   if curr->byte == ','                  # comment token
 5692     #     ++in->read
 5693     #     goto start
 5694     #   if curr-byte == '#'                   # comment
 5695     #     goto done                             # treat as eof
 5696     #   if curr-byte == '"'                   # string literal
 5697     #     skip-string(in)
 5698     #     goto done                           # no metadata
 5699     #   if curr-byte == '('
 5700     #     ++in->read
 5701     #     goto done
 5702     #   if curr-byte == ')'
 5703     #     ++in->read
 5704     #     goto done
 5705     #   # read a word
 5706     #   while true
 5707     #     if in->read >= in->write
 5708     #       break
 5709     #     curr-byte = in->data[in->read]
 5710     #     if curr-byte == ' '
 5711     #       break
 5712     #     if curr-byte == '\r'
 5713     #       break
 5714     #     if curr-byte == '\n'
 5715     #       break
 5716     #     if curr-byte == '('
 5717     #       break
 5718     #     if curr-byte == ')'
 5719     #       break
 5720     #     if curr-byte == ','
 5721     #       break
 5722     #     ++in->read
 5723     # done:
 5724     #   out->end = &in->data[in->read]
 5725     #
 5726     # . prologue
 5727     55/push-ebp
 5728     89/<- %ebp 4/r32/esp
 5729     # . save registers
 5730     50/push-eax
 5731     51/push-ecx
 5732     56/push-esi
 5733     57/push-edi
 5734     # esi = in
 5735     8b/-> *(ebp+8) 6/r32/esi
 5736     # edi = out
 5737     8b/-> *(ebp+0xc) 7/r32/edi
 5738 $next-mu-token:start:
 5739     (skip-chars-matching-whitespace %esi)
 5740 $next-mu-token:check0:
 5741     # if (in->read >= in->write) return out = {0, 0}
 5742     # . ecx = in->read
 5743     8b/-> *(esi+4) 1/r32/ecx
 5744     # . if (ecx >= in->write) return out = {0, 0}
 5745     3b/compare<- *esi 1/r32/ecx
 5746     c7 0/subop/copy *edi 0/imm32
 5747     c7 0/subop/copy *(edi+4) 0/imm32
 5748     0f 8d/jump-if->= $next-mu-token:end/disp32
 5749     # out->start = &in->data[in->read]
 5750     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 5751     89/<- *edi 0/r32/eax
 5752     # var curr-byte/eax: byte = in->data[in->read]
 5753     31/xor-with %eax 0/r32/eax
 5754     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 5755     {
 5756 $next-mu-token:check-for-comma:
 5757       # if (curr-byte != ',') break
 5758       3d/compare-eax-and 0x2c/imm32/comma
 5759       75/jump-if-!= break/disp8
 5760       # ++in->read
 5761       ff 0/subop/increment *(esi+4)
 5762       # restart
 5763       e9/jump $next-mu-token:start/disp32
 5764     }
 5765     {
 5766 $next-mu-token:check-for-comment:
 5767       # if (curr-byte != '#') break
 5768       3d/compare-eax-and 0x23/imm32/pound
 5769       75/jump-if-!= break/disp8
 5770       # return eof
 5771       e9/jump $next-mu-token:done/disp32
 5772     }
 5773     {
 5774 $next-mu-token:check-for-string-literal:
 5775       # if (curr-byte != '"') break
 5776       3d/compare-eax-and 0x22/imm32/dquote
 5777       75/jump-if-!= break/disp8
 5778       (skip-string %esi)
 5779       # return
 5780       e9/jump $next-mu-token:done/disp32
 5781     }
 5782     {
 5783 $next-mu-token:check-for-open-paren:
 5784       # if (curr-byte != '(') break
 5785       3d/compare-eax-and 0x28/imm32/open-paren
 5786       75/jump-if-!= break/disp8
 5787       # ++in->read
 5788       ff 0/subop/increment *(esi+4)
 5789       # return
 5790       e9/jump $next-mu-token:done/disp32
 5791     }
 5792     {
 5793 $next-mu-token:check-for-close-paren:
 5794       # if (curr-byte != ')') break
 5795       3d/compare-eax-and 0x29/imm32/close-paren
 5796       75/jump-if-!= break/disp8
 5797       # ++in->read
 5798       ff 0/subop/increment *(esi+4)
 5799       # return
 5800       e9/jump $next-mu-token:done/disp32
 5801     }
 5802     {
 5803 $next-mu-token:regular-word-without-metadata:
 5804       # if (in->read >= in->write) break
 5805       # . ecx = in->read
 5806       8b/-> *(esi+4) 1/r32/ecx
 5807       # . if (ecx >= in->write) break
 5808       3b/compare<- *esi 1/r32/ecx
 5809       7d/jump-if->= break/disp8
 5810       # var c/eax: byte = in->data[in->read]
 5811       31/xor-with %eax 0/r32/eax
 5812       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 5813       # if (c == ' ') break
 5814       3d/compare-eax-and 0x20/imm32/space
 5815       74/jump-if-= break/disp8
 5816       # if (c == '\r') break
 5817       3d/compare-eax-and 0xd/imm32/carriage-return
 5818       74/jump-if-= break/disp8
 5819       # if (c == '\n') break
 5820       3d/compare-eax-and 0xa/imm32/newline
 5821       74/jump-if-= break/disp8
 5822       # if (c == '(') break
 5823       3d/compare-eax-and 0x28/imm32/open-paren
 5824       0f 84/jump-if-= break/disp32
 5825       # if (c == ')') break
 5826       3d/compare-eax-and 0x29/imm32/close-paren
 5827       0f 84/jump-if-= break/disp32
 5828       # if (c == ',') break
 5829       3d/compare-eax-and 0x2c/imm32/comma
 5830       0f 84/jump-if-= break/disp32
 5831       # ++in->read
 5832       ff 0/subop/increment *(esi+4)
 5833       #
 5834       e9/jump loop/disp32
 5835     }
 5836 $next-mu-token:done:
 5837     # out->end = &in->data[in->read]
 5838     8b/-> *(esi+4) 1/r32/ecx
 5839     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 5840     89/<- *(edi+4) 0/r32/eax
 5841 $next-mu-token:end:
 5842     # . restore registers
 5843     5f/pop-to-edi
 5844     5e/pop-to-esi
 5845     59/pop-to-ecx
 5846     58/pop-to-eax
 5847     # . epilogue
 5848     89/<- %esp 5/r32/ebp
 5849     5d/pop-to-ebp
 5850     c3/return
 5851 
 5852 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 5853     # . prologue
 5854     55/push-ebp
 5855     89/<- %ebp 4/r32/esp
 5856     # if (pos-slice(arr, s) != -1) return it
 5857     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 5858     3d/compare-eax-and -1/imm32
 5859     75/jump-if-!= $pos-or-insert-slice:end/disp8
 5860 $pos-or-insert-slice:insert:
 5861     # var s2/eax: (handle array byte)
 5862     68/push 0/imm32
 5863     68/push 0/imm32
 5864     89/<- %eax 4/r32/esp
 5865     (slice-to-string Heap *(ebp+0xc) %eax)
 5866     # throw away alloc-id
 5867     (lookup *eax *(eax+4))  # => eax
 5868     (write-int *(ebp+8) %eax)
 5869     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 5870 $pos-or-insert-slice:end:
 5871     # . reclaim locals
 5872     81 0/subop/add %esp 8/imm32
 5873     # . epilogue
 5874     89/<- %esp 5/r32/ebp
 5875     5d/pop-to-ebp
 5876     c3/return
 5877 
 5878 # return the index in an array of strings matching 's', -1 if not found
 5879 # index is denominated in elements, not bytes
 5880 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 5881     # . prologue
 5882     55/push-ebp
 5883     89/<- %ebp 4/r32/esp
 5884     # . save registers
 5885     51/push-ecx
 5886     52/push-edx
 5887     53/push-ebx
 5888     56/push-esi
 5889 #?     (write-buffered Stderr "pos-slice: ")
 5890 #?     (write-slice-buffered Stderr *(ebp+0xc))
 5891 #?     (write-buffered Stderr "\n")
 5892 #?     (flush Stderr)
 5893     # esi = arr
 5894     8b/-> *(ebp+8) 6/r32/esi
 5895     # var index/ecx: int = 0
 5896     b9/copy-to-ecx 0/imm32
 5897     # var curr/edx: (addr (addr array byte)) = arr->data
 5898     8d/copy-address *(esi+0xc) 2/r32/edx
 5899     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 5900     8b/-> *esi 3/r32/ebx
 5901     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 5902     {
 5903 #?       (write-buffered Stderr "  ")
 5904 #?       (print-int32-buffered Stderr %ecx)
 5905 #?       (write-buffered Stderr "\n")
 5906 #?       (flush Stderr)
 5907       # if (curr >= max) return -1
 5908       39/compare %edx 3/r32/ebx
 5909       b8/copy-to-eax -1/imm32
 5910       73/jump-if-addr>= $pos-slice:end/disp8
 5911       # if (slice-equal?(s, *curr)) break
 5912       (slice-equal? *(ebp+0xc) *edx)  # => eax
 5913       3d/compare-eax-and 0/imm32/false
 5914       75/jump-if-!= break/disp8
 5915       # ++index
 5916       41/increment-ecx
 5917       # curr += 4
 5918       81 0/subop/add %edx 4/imm32
 5919       #
 5920       eb/jump loop/disp8
 5921     }
 5922     # return index
 5923     89/<- %eax 1/r32/ecx
 5924 $pos-slice:end:
 5925 #?     (write-buffered Stderr "=> ")
 5926 #?     (print-int32-buffered Stderr %eax)
 5927 #?     (write-buffered Stderr "\n")
 5928     # . restore registers
 5929     5e/pop-to-esi
 5930     5b/pop-to-ebx
 5931     5a/pop-to-edx
 5932     59/pop-to-ecx
 5933     # . epilogue
 5934     89/<- %esp 5/r32/ebp
 5935     5d/pop-to-ebp
 5936     c3/return
 5937 
 5938 test-parse-var-with-type:
 5939     # . prologue
 5940     55/push-ebp
 5941     89/<- %ebp 4/r32/esp
 5942     # (eax..ecx) = "x:"
 5943     b8/copy-to-eax "x:"/imm32
 5944     8b/-> *eax 1/r32/ecx
 5945     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5946     05/add-to-eax 4/imm32
 5947     # var slice/ecx: slice = {eax, ecx}
 5948     51/push-ecx
 5949     50/push-eax
 5950     89/<- %ecx 4/r32/esp
 5951     # _test-input-stream contains "int"
 5952     (clear-stream _test-input-stream)
 5953     (write _test-input-stream "int")
 5954     # var v/edx: (handle var)
 5955     68/push 0/imm32
 5956     68/push 0/imm32
 5957     89/<- %edx 4/r32/esp
 5958     #
 5959     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5960     # var v-addr/edx: (addr var) = lookup(v)
 5961     (lookup *edx *(edx+4))  # => eax
 5962     89/<- %edx 0/r32/eax
 5963     # check v-addr->name
 5964     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5965     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 5966     # check v-addr->type
 5967     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5968     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 5969     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 5970     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 5971     # . epilogue
 5972     89/<- %esp 5/r32/ebp
 5973     5d/pop-to-ebp
 5974     c3/return
 5975 
 5976 test-parse-var-with-type-and-register:
 5977     # . prologue
 5978     55/push-ebp
 5979     89/<- %ebp 4/r32/esp
 5980     # (eax..ecx) = "x/eax:"
 5981     b8/copy-to-eax "x/eax:"/imm32
 5982     8b/-> *eax 1/r32/ecx
 5983     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5984     05/add-to-eax 4/imm32
 5985     # var slice/ecx: slice = {eax, ecx}
 5986     51/push-ecx
 5987     50/push-eax
 5988     89/<- %ecx 4/r32/esp
 5989     # _test-input-stream contains "int"
 5990     (clear-stream _test-input-stream)
 5991     (write _test-input-stream "int")
 5992     # var v/edx: (handle var)
 5993     68/push 0/imm32
 5994     68/push 0/imm32
 5995     89/<- %edx 4/r32/esp
 5996     #
 5997     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5998     # var v-addr/edx: (addr var) = lookup(v)
 5999     (lookup *edx *(edx+4))  # => eax
 6000     89/<- %edx 0/r32/eax
 6001     # check v-addr->name
 6002     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6003     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 6004     # check v-addr->register
 6005     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 6006     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 6007     # check v-addr->type
 6008     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6009     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 6010     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 6011     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 6012     # . epilogue
 6013     89/<- %esp 5/r32/ebp
 6014     5d/pop-to-ebp
 6015     c3/return
 6016 
 6017 test-parse-var-with-trailing-characters:
 6018     # . prologue
 6019     55/push-ebp
 6020     89/<- %ebp 4/r32/esp
 6021     # (eax..ecx) = "x:"
 6022     b8/copy-to-eax "x:"/imm32
 6023     8b/-> *eax 1/r32/ecx
 6024     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6025     05/add-to-eax 4/imm32
 6026     # var slice/ecx: slice = {eax, ecx}
 6027     51/push-ecx
 6028     50/push-eax
 6029     89/<- %ecx 4/r32/esp
 6030     # _test-input-stream contains "int,"
 6031     (clear-stream _test-input-stream)
 6032     (write _test-input-stream "int,")
 6033     # var v/edx: (handle var)
 6034     68/push 0/imm32
 6035     68/push 0/imm32
 6036     89/<- %edx 4/r32/esp
 6037     #
 6038     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6039     # var v-addr/edx: (addr var) = lookup(v)
 6040     (lookup *edx *(edx+4))  # => eax
 6041     89/<- %edx 0/r32/eax
 6042     # check v-addr->name
 6043     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6044     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 6045     # check v-addr->register
 6046     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 6047     # check v-addr->type
 6048     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6049     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 6050     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 6051     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 6052     # . epilogue
 6053     89/<- %esp 5/r32/ebp
 6054     5d/pop-to-ebp
 6055     c3/return
 6056 
 6057 test-parse-var-with-register-and-trailing-characters:
 6058     # . prologue
 6059     55/push-ebp
 6060     89/<- %ebp 4/r32/esp
 6061     # (eax..ecx) = "x/eax:"
 6062     b8/copy-to-eax "x/eax:"/imm32
 6063     8b/-> *eax 1/r32/ecx
 6064     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6065     05/add-to-eax 4/imm32
 6066     # var slice/ecx: slice = {eax, ecx}
 6067     51/push-ecx
 6068     50/push-eax
 6069     89/<- %ecx 4/r32/esp
 6070     # _test-input-stream contains "int,"
 6071     (clear-stream _test-input-stream)
 6072     (write _test-input-stream "int,")
 6073     # var v/edx: (handle var)
 6074     68/push 0/imm32
 6075     68/push 0/imm32
 6076     89/<- %edx 4/r32/esp
 6077     #
 6078     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6079     # var v-addr/edx: (addr var) = lookup(v)
 6080     (lookup *edx *(edx+4))  # => eax
 6081     89/<- %edx 0/r32/eax
 6082     # check v-addr->name
 6083     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6084     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 6085     # check v-addr->register
 6086     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 6087     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 6088     # check v-addr->type
 6089     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6090     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 6091     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 6092     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 6093     # . epilogue
 6094     89/<- %esp 5/r32/ebp
 6095     5d/pop-to-ebp
 6096     c3/return
 6097 
 6098 test-parse-var-with-compound-type:
 6099     # . prologue
 6100     55/push-ebp
 6101     89/<- %ebp 4/r32/esp
 6102     # (eax..ecx) = "x:"
 6103     b8/copy-to-eax "x:"/imm32
 6104     8b/-> *eax 1/r32/ecx
 6105     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6106     05/add-to-eax 4/imm32
 6107     # var slice/ecx: slice = {eax, ecx}
 6108     51/push-ecx
 6109     50/push-eax
 6110     89/<- %ecx 4/r32/esp
 6111     # _test-input-stream contains "(addr int)"
 6112     (clear-stream _test-input-stream)
 6113     (write _test-input-stream "(addr int)")
 6114     # var v/edx: (handle var)
 6115     68/push 0/imm32
 6116     68/push 0/imm32
 6117     89/<- %edx 4/r32/esp
 6118     #
 6119     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 6120     # var v-addr/edx: (addr var) = lookup(v)
 6121     (lookup *edx *(edx+4))  # => eax
 6122     89/<- %edx 0/r32/eax
 6123     # check v-addr->name
 6124     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6125     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 6126     # check v-addr->register
 6127     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 6128     # - check v-addr->type
 6129     # var type/edx: (addr tree type-id) = var->type
 6130     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6131     89/<- %edx 0/r32/eax
 6132     # type is a non-atom
 6133     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 6134     # type->left == atom(addr)
 6135     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 6136     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 6137     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 6138     # type->right->left == atom(int)
 6139     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 6140     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 6141     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 6142     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 6143     # type->right->right == null
 6144     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 6145     # . epilogue
 6146     89/<- %esp 5/r32/ebp
 6147     5d/pop-to-ebp
 6148     c3/return
 6149 
 6150 # identifier starts with a letter or '$' or '_'
 6151 # no constraints at the moment on later letters
 6152 # all we really want to do so far is exclude '{', '}' and '->'
 6153 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 6154     # . prologue
 6155     55/push-ebp
 6156     89/<- %ebp 4/r32/esp
 6157     # if (slice-empty?(in)) return false
 6158     (slice-empty? *(ebp+8))  # => eax
 6159     3d/compare-eax-and 0/imm32/false
 6160     75/jump-if-!= $is-identifier?:false/disp8
 6161     # var c/eax: byte = *in->start
 6162     8b/-> *(ebp+8) 0/r32/eax
 6163     8b/-> *eax 0/r32/eax
 6164     8a/copy-byte *eax 0/r32/AL
 6165     81 4/subop/and %eax 0xff/imm32
 6166     # if (c == '$') return true
 6167     3d/compare-eax-and 0x24/imm32/$
 6168     74/jump-if-= $is-identifier?:true/disp8
 6169     # if (c == '_') return true
 6170     3d/compare-eax-and 0x5f/imm32/_
 6171     74/jump-if-= $is-identifier?:true/disp8
 6172     # drop case
 6173     25/and-eax-with 0x5f/imm32
 6174     # if (c < 'A') return false
 6175     3d/compare-eax-and 0x41/imm32/A
 6176     7c/jump-if-< $is-identifier?:false/disp8
 6177     # if (c > 'Z') return false
 6178     3d/compare-eax-and 0x5a/imm32/Z
 6179     7f/jump-if-> $is-identifier?:false/disp8
 6180     # otherwise return true
 6181 $is-identifier?:true:
 6182     b8/copy-to-eax 1/imm32/true
 6183     eb/jump $is-identifier?:end/disp8
 6184 $is-identifier?:false:
 6185     b8/copy-to-eax 0/imm32/false
 6186 $is-identifier?:end:
 6187     # . epilogue
 6188     89/<- %esp 5/r32/ebp
 6189     5d/pop-to-ebp
 6190     c3/return
 6191 
 6192 test-is-identifier-dollar:
 6193     # . prologue
 6194     55/push-ebp
 6195     89/<- %ebp 4/r32/esp
 6196     # (eax..ecx) = "$a"
 6197     b8/copy-to-eax "$a"/imm32
 6198     8b/-> *eax 1/r32/ecx
 6199     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6200     05/add-to-eax 4/imm32
 6201     # var slice/ecx: slice = {eax, ecx}
 6202     51/push-ecx
 6203     50/push-eax
 6204     89/<- %ecx 4/r32/esp
 6205     #
 6206     (is-identifier? %ecx)
 6207     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 6208     # . epilogue
 6209     89/<- %esp 5/r32/ebp
 6210     5d/pop-to-ebp
 6211     c3/return
 6212 
 6213 test-is-identifier-underscore:
 6214     # . prologue
 6215     55/push-ebp
 6216     89/<- %ebp 4/r32/esp
 6217     # (eax..ecx) = "_a"
 6218     b8/copy-to-eax "_a"/imm32
 6219     8b/-> *eax 1/r32/ecx
 6220     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6221     05/add-to-eax 4/imm32
 6222     # var slice/ecx: slice = {eax, ecx}
 6223     51/push-ecx
 6224     50/push-eax
 6225     89/<- %ecx 4/r32/esp
 6226     #
 6227     (is-identifier? %ecx)
 6228     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 6229     # . epilogue
 6230     89/<- %esp 5/r32/ebp
 6231     5d/pop-to-ebp
 6232     c3/return
 6233 
 6234 test-is-identifier-a:
 6235     # . prologue
 6236     55/push-ebp
 6237     89/<- %ebp 4/r32/esp
 6238     # (eax..ecx) = "a$"
 6239     b8/copy-to-eax "a$"/imm32
 6240     8b/-> *eax 1/r32/ecx
 6241     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6242     05/add-to-eax 4/imm32
 6243     # var slice/ecx: slice = {eax, ecx}
 6244     51/push-ecx
 6245     50/push-eax
 6246     89/<- %ecx 4/r32/esp
 6247     #
 6248     (is-identifier? %ecx)
 6249     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 6250     # . epilogue
 6251     89/<- %esp 5/r32/ebp
 6252     5d/pop-to-ebp
 6253     c3/return
 6254 
 6255 test-is-identifier-z:
 6256     # . prologue
 6257     55/push-ebp
 6258     89/<- %ebp 4/r32/esp
 6259     # (eax..ecx) = "z$"
 6260     b8/copy-to-eax "z$"/imm32
 6261     8b/-> *eax 1/r32/ecx
 6262     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6263     05/add-to-eax 4/imm32
 6264     # var slice/ecx: slice = {eax, ecx}
 6265     51/push-ecx
 6266     50/push-eax
 6267     89/<- %ecx 4/r32/esp
 6268     #
 6269     (is-identifier? %ecx)
 6270     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 6271     # . epilogue
 6272     89/<- %esp 5/r32/ebp
 6273     5d/pop-to-ebp
 6274     c3/return
 6275 
 6276 test-is-identifier-A:
 6277     # . prologue
 6278     55/push-ebp
 6279     89/<- %ebp 4/r32/esp
 6280     # (eax..ecx) = "A$"
 6281     b8/copy-to-eax "A$"/imm32
 6282     8b/-> *eax 1/r32/ecx
 6283     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6284     05/add-to-eax 4/imm32
 6285     # var slice/ecx: slice = {eax, ecx}
 6286     51/push-ecx
 6287     50/push-eax
 6288     89/<- %ecx 4/r32/esp
 6289     #
 6290     (is-identifier? %ecx)
 6291     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 6292     # . epilogue
 6293     89/<- %esp 5/r32/ebp
 6294     5d/pop-to-ebp
 6295     c3/return
 6296 
 6297 test-is-identifier-Z:
 6298     # . prologue
 6299     55/push-ebp
 6300     89/<- %ebp 4/r32/esp
 6301     # (eax..ecx) = "Z$"
 6302     b8/copy-to-eax "Z$"/imm32
 6303     8b/-> *eax 1/r32/ecx
 6304     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6305     05/add-to-eax 4/imm32
 6306     # var slice/ecx: slice = {eax, ecx}
 6307     51/push-ecx
 6308     50/push-eax
 6309     89/<- %ecx 4/r32/esp
 6310     #
 6311     (is-identifier? %ecx)
 6312     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 6313     # . epilogue
 6314     89/<- %esp 5/r32/ebp
 6315     5d/pop-to-ebp
 6316     c3/return
 6317 
 6318 test-is-identifier-at:
 6319     # character before 'A' is invalid
 6320     # . prologue
 6321     55/push-ebp
 6322     89/<- %ebp 4/r32/esp
 6323     # (eax..ecx) = "@a"
 6324     b8/copy-to-eax "@a"/imm32
 6325     8b/-> *eax 1/r32/ecx
 6326     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6327     05/add-to-eax 4/imm32
 6328     # var slice/ecx: slice = {eax, ecx}
 6329     51/push-ecx
 6330     50/push-eax
 6331     89/<- %ecx 4/r32/esp
 6332     #
 6333     (is-identifier? %ecx)
 6334     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 6335     # . epilogue
 6336     89/<- %esp 5/r32/ebp
 6337     5d/pop-to-ebp
 6338     c3/return
 6339 
 6340 test-is-identifier-square-bracket:
 6341     # character after 'Z' is invalid
 6342     # . prologue
 6343     55/push-ebp
 6344     89/<- %ebp 4/r32/esp
 6345     # (eax..ecx) = "[a"
 6346     b8/copy-to-eax "[a"/imm32
 6347     8b/-> *eax 1/r32/ecx
 6348     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6349     05/add-to-eax 4/imm32
 6350     # var slice/ecx: slice = {eax, ecx}
 6351     51/push-ecx
 6352     50/push-eax
 6353     89/<- %ecx 4/r32/esp
 6354     #
 6355     (is-identifier? %ecx)
 6356     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 6357     # . epilogue
 6358     89/<- %esp 5/r32/ebp
 6359     5d/pop-to-ebp
 6360     c3/return
 6361 
 6362 test-is-identifier-backtick:
 6363     # character before 'a' is invalid
 6364     # . prologue
 6365     55/push-ebp
 6366     89/<- %ebp 4/r32/esp
 6367     # (eax..ecx) = "`a"
 6368     b8/copy-to-eax "`a"/imm32
 6369     8b/-> *eax 1/r32/ecx
 6370     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6371     05/add-to-eax 4/imm32
 6372     # var slice/ecx: slice = {eax, ecx}
 6373     51/push-ecx
 6374     50/push-eax
 6375     89/<- %ecx 4/r32/esp
 6376     #
 6377     (is-identifier? %ecx)
 6378     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 6379     # . epilogue
 6380     89/<- %esp 5/r32/ebp
 6381     5d/pop-to-ebp
 6382     c3/return
 6383 
 6384 test-is-identifier-curly-brace-open:
 6385     # character after 'z' is invalid; also used for blocks
 6386     # . prologue
 6387     55/push-ebp
 6388     89/<- %ebp 4/r32/esp
 6389     # (eax..ecx) = "{a"
 6390     b8/copy-to-eax "{a"/imm32
 6391     8b/-> *eax 1/r32/ecx
 6392     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6393     05/add-to-eax 4/imm32
 6394     # var slice/ecx: slice = {eax, ecx}
 6395     51/push-ecx
 6396     50/push-eax
 6397     89/<- %ecx 4/r32/esp
 6398     #
 6399     (is-identifier? %ecx)
 6400     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 6401     # . epilogue
 6402     89/<- %esp 5/r32/ebp
 6403     5d/pop-to-ebp
 6404     c3/return
 6405 
 6406 test-is-identifier-curly-brace-close:
 6407     # . prologue
 6408     55/push-ebp
 6409     89/<- %ebp 4/r32/esp
 6410     # (eax..ecx) = "}a"
 6411     b8/copy-to-eax "}a"/imm32
 6412     8b/-> *eax 1/r32/ecx
 6413     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6414     05/add-to-eax 4/imm32
 6415     # var slice/ecx: slice = {eax, ecx}
 6416     51/push-ecx
 6417     50/push-eax
 6418     89/<- %ecx 4/r32/esp
 6419     #
 6420     (is-identifier? %ecx)
 6421     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 6422     # . epilogue
 6423     89/<- %esp 5/r32/ebp
 6424     5d/pop-to-ebp
 6425     c3/return
 6426 
 6427 test-is-identifier-hyphen:
 6428     # disallow leading '-' since '->' has special meaning
 6429     # . prologue
 6430     55/push-ebp
 6431     89/<- %ebp 4/r32/esp
 6432     # (eax..ecx) = "-a"
 6433     b8/copy-to-eax "-a"/imm32
 6434     8b/-> *eax 1/r32/ecx
 6435     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 6436     05/add-to-eax 4/imm32
 6437     # var slice/ecx: slice = {eax, ecx}
 6438     51/push-ecx
 6439     50/push-eax
 6440     89/<- %ecx 4/r32/esp
 6441     #
 6442     (is-identifier? %ecx)
 6443     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 6444     # . epilogue
 6445     89/<- %esp 5/r32/ebp
 6446     5d/pop-to-ebp
 6447     c3/return
 6448 
 6449 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6450     # . prologue
 6451     55/push-ebp
 6452     89/<- %ebp 4/r32/esp
 6453     # . save registers
 6454     50/push-eax
 6455     56/push-esi
 6456     57/push-edi
 6457     # esi = in
 6458     8b/-> *(ebp+8) 6/r32/esi
 6459     # edi = out
 6460     8b/-> *(ebp+0xc) 7/r32/edi
 6461     # parse-mu-block(in, vars, out, out->body)
 6462     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 6463     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 6464 $populate-mu-function-body:end:
 6465     # . restore registers
 6466     5f/pop-to-edi
 6467     5e/pop-to-esi
 6468     58/pop-to-eax
 6469     # . epilogue
 6470     89/<- %esp 5/r32/ebp
 6471     5d/pop-to-ebp
 6472     c3/return
 6473 
 6474 # parses a block, assuming that the leading '{' has already been read by the caller
 6475 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)
 6476     # pseudocode:
 6477     #   var line: (stream byte 512)
 6478     #   var word-slice: slice
 6479     #   allocate(Heap, Stmt-size, out)
 6480     #   var out-addr: (addr block) = lookup(*out)
 6481     #   out-addr->tag = 0/block
 6482     #   out-addr->var = some unique name
 6483     #   push(vars, {out-addr->var, false})
 6484     #   while true                                  # line loop
 6485     #     clear-stream(line)
 6486     #     read-line-buffered(in, line)
 6487     #     if (line->write == 0) break               # end of file
 6488     #     word-slice = next-mu-token(line)
 6489     #     if slice-empty?(word-slice)               # end of line
 6490     #       continue
 6491     #     else if slice-starts-with?(word-slice, "#")
 6492     #       continue
 6493     #     else if slice-equal?(word-slice, "{")
 6494     #       assert(no-tokens-in(line))
 6495     #       block = parse-mu-block(in, vars, fn)
 6496     #       append-to-block(out-addr, block)
 6497     #     else if slice-equal?(word-slice, "}")
 6498     #       break
 6499     #     else if slice-ends-with?(word-slice, ":")
 6500     #       # TODO: error-check the rest of 'line'
 6501     #       --word-slice->end to skip ':'
 6502     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 6503     #       append-to-block(out-addr, named-block)
 6504     #     else if slice-equal?(word-slice, "var")
 6505     #       var-def = parse-mu-var-def(line, vars, fn)
 6506     #       append-to-block(out-addr, var-def)
 6507     #     else
 6508     #       stmt = parse-mu-stmt(line, vars, fn)
 6509     #       append-to-block(out-addr, stmt)
 6510     #   pop(vars)
 6511     #
 6512     # . prologue
 6513     55/push-ebp
 6514     89/<- %ebp 4/r32/esp
 6515     # . save registers
 6516     50/push-eax
 6517     51/push-ecx
 6518     52/push-edx
 6519     53/push-ebx
 6520     57/push-edi
 6521     # var line/ecx: (stream byte 512)
 6522     81 5/subop/subtract %esp 0x200/imm32
 6523     68/push 0x200/imm32/size
 6524     68/push 0/imm32/read
 6525     68/push 0/imm32/write
 6526     89/<- %ecx 4/r32/esp
 6527     # var word-slice/edx: slice
 6528     68/push 0/imm32/end
 6529     68/push 0/imm32/start
 6530     89/<- %edx 4/r32/esp
 6531     # allocate into out
 6532     (allocate Heap *Stmt-size *(ebp+0x14))
 6533     # var out-addr/edi: (addr block) = lookup(*out)
 6534     8b/-> *(ebp+0x14) 7/r32/edi
 6535     (lookup *edi *(edi+4))  # => eax
 6536     89/<- %edi 0/r32/eax
 6537     # out-addr->tag is 0 (block) by default
 6538     # set out-addr->var
 6539     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 6540     (new-block-name *(ebp+0x10) %eax)
 6541     # push(vars, out-addr->var)
 6542     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 6543     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 6544     (push *(ebp+0xc) 0)  # false
 6545     {
 6546 $parse-mu-block:line-loop:
 6547       # line = read-line-buffered(in)
 6548       (clear-stream %ecx)
 6549       (read-line-buffered *(ebp+8) %ecx)
 6550 #?       (write-buffered Stderr "line: ")
 6551 #?       (write-stream-data Stderr %ecx)
 6552 #?       (write-buffered Stderr Newline)
 6553 #?       (flush Stderr)
 6554       # if (line->write == 0) break
 6555       81 7/subop/compare *ecx 0/imm32
 6556       0f 84/jump-if-= break/disp32
 6557       # word-slice = next-mu-token(line)
 6558       (next-mu-token %ecx %edx)
 6559 #?       (write-buffered Stderr "word: ")
 6560 #?       (write-slice-buffered Stderr %edx)
 6561 #?       (write-buffered Stderr Newline)
 6562 #?       (flush Stderr)
 6563       # if slice-empty?(word-slice) continue
 6564       (slice-empty? %edx)
 6565       3d/compare-eax-and 0/imm32/false
 6566       0f 85/jump-if-!= loop/disp32
 6567       # if (slice-starts-with?(word-slice, '#') continue
 6568       # . eax = *word-slice->start
 6569       8b/-> *edx 0/r32/eax
 6570       8a/copy-byte *eax 0/r32/AL
 6571       81 4/subop/and %eax 0xff/imm32
 6572       # . if (eax == '#') continue
 6573       3d/compare-eax-and 0x23/imm32/hash
 6574       0f 84/jump-if-= loop/disp32
 6575       # if slice-equal?(word-slice, "{")
 6576       {
 6577 $parse-mu-block:check-for-block:
 6578         (slice-equal? %edx "{")
 6579         3d/compare-eax-and 0/imm32/false
 6580         74/jump-if-= break/disp8
 6581         (check-no-tokens-left %ecx)
 6582         # parse new block and append
 6583         # . var tmp/eax: (handle block)
 6584         68/push 0/imm32
 6585         68/push 0/imm32
 6586         89/<- %eax 4/r32/esp
 6587         # .
 6588         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6589         (append-to-block Heap %edi  *eax *(eax+4))
 6590         # . reclaim tmp
 6591         81 0/subop/add %esp 8/imm32
 6592         # .
 6593         e9/jump $parse-mu-block:line-loop/disp32
 6594       }
 6595       # if slice-equal?(word-slice, "}") break
 6596 $parse-mu-block:check-for-end:
 6597       (slice-equal? %edx "}")
 6598       3d/compare-eax-and 0/imm32/false
 6599       0f 85/jump-if-!= break/disp32
 6600       # if slice-ends-with?(word-slice, ":") parse named block and append
 6601       {
 6602 $parse-mu-block:check-for-named-block:
 6603         # . eax = *(word-slice->end-1)
 6604         8b/-> *(edx+4) 0/r32/eax
 6605         48/decrement-eax
 6606         8a/copy-byte *eax 0/r32/AL
 6607         81 4/subop/and %eax 0xff/imm32
 6608         # . if (eax != ':') break
 6609         3d/compare-eax-and 0x3a/imm32/colon
 6610         0f 85/jump-if-!= break/disp32
 6611         # TODO: error-check the rest of 'line'
 6612         #
 6613         # skip ':'
 6614         ff 1/subop/decrement *(edx+4)  # Slice-end
 6615         # var tmp/eax: (handle block)
 6616         68/push 0/imm32
 6617         68/push 0/imm32
 6618         89/<- %eax 4/r32/esp
 6619         #
 6620         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6621         (append-to-block Heap %edi  *eax *(eax+4))
 6622         # reclaim tmp
 6623         81 0/subop/add %esp 8/imm32
 6624         #
 6625         e9/jump $parse-mu-block:line-loop/disp32
 6626       }
 6627       # if slice-equal?(word-slice, "var")
 6628       {
 6629 $parse-mu-block:check-for-var:
 6630         (slice-equal? %edx "var")
 6631         3d/compare-eax-and 0/imm32/false
 6632         74/jump-if-= break/disp8
 6633         # var tmp/eax: (handle block)
 6634         68/push 0/imm32
 6635         68/push 0/imm32
 6636         89/<- %eax 4/r32/esp
 6637         #
 6638         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 6639         (append-to-block Heap %edi  *eax *(eax+4))
 6640         # reclaim tmp
 6641         81 0/subop/add %esp 8/imm32
 6642         #
 6643         e9/jump $parse-mu-block:line-loop/disp32
 6644       }
 6645 $parse-mu-block:regular-stmt:
 6646       # otherwise
 6647       # var tmp/eax: (handle block)
 6648       68/push 0/imm32
 6649       68/push 0/imm32
 6650       89/<- %eax 4/r32/esp
 6651       #
 6652       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 6653       (append-to-block Heap %edi  *eax *(eax+4))
 6654       # reclaim tmp
 6655       81 0/subop/add %esp 8/imm32
 6656       #
 6657       e9/jump loop/disp32
 6658     } # end line loop
 6659     # pop(vars)
 6660     (pop *(ebp+0xc))  # => eax
 6661     (pop *(ebp+0xc))  # => eax
 6662     (pop *(ebp+0xc))  # => eax
 6663 $parse-mu-block:end:
 6664     # . reclaim locals
 6665     81 0/subop/add %esp 0x214/imm32
 6666     # . restore registers
 6667     5f/pop-to-edi
 6668     5b/pop-to-ebx
 6669     5a/pop-to-edx
 6670     59/pop-to-ecx
 6671     58/pop-to-eax
 6672     # . epilogue
 6673     89/<- %esp 5/r32/ebp
 6674     5d/pop-to-ebp
 6675     c3/return
 6676 
 6677 $parse-mu-block:abort:
 6678     # error("'{' or '}' should be on its own line, but got '")
 6679     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 6680     (rewind-stream %ecx)
 6681     (write-stream-data *(ebp+0x18) %ecx)
 6682     (write-buffered *(ebp+0x18) "'\n")
 6683     (flush *(ebp+0x18))
 6684     (stop *(ebp+0x1c) 1)
 6685     # never gets here
 6686 
 6687 new-block-name:  # fn: (addr function), out: (addr handle var)
 6688     # . prologue
 6689     55/push-ebp
 6690     89/<- %ebp 4/r32/esp
 6691     # . save registers
 6692     50/push-eax
 6693     51/push-ecx
 6694     52/push-edx
 6695     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 6696     8b/-> *(ebp+8) 0/r32/eax
 6697     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 6698     8b/-> *eax 0/r32/eax  # String-size
 6699     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 6700     89/<- %ecx 0/r32/eax
 6701     # var name/edx: (stream byte n)
 6702     29/subtract-from %esp 1/r32/ecx
 6703     ff 6/subop/push %ecx
 6704     68/push 0/imm32/read
 6705     68/push 0/imm32/write
 6706     89/<- %edx 4/r32/esp
 6707     (clear-stream %edx)
 6708     # eax = fn->name
 6709     8b/-> *(ebp+8) 0/r32/eax
 6710     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 6711     # construct result using Next-block-index (and increment it)
 6712     (write %edx "$")
 6713     (write %edx %eax)
 6714     (write %edx ":")
 6715     (print-int32 %edx *Next-block-index)
 6716     ff 0/subop/increment *Next-block-index
 6717     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 6718     # . eax = name->write
 6719     8b/-> *edx 0/r32/eax
 6720     # . edx = name->data
 6721     8d/copy-address *(edx+0xc) 2/r32/edx
 6722     # . eax = name->write + name->data
 6723     01/add-to %eax 2/r32/edx
 6724     # . push {edx, eax}
 6725     ff 6/subop/push %eax
 6726     ff 6/subop/push %edx
 6727     89/<- %eax 4/r32/esp
 6728     # out = new literal(s)
 6729     (new-literal Heap %eax *(ebp+0xc))
 6730 #?     8b/-> *(ebp+0xc) 0/r32/eax
 6731 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 6732 #?     (print-int32-buffered Stderr *(eax+8))
 6733 #?     (write-buffered Stderr " for var ")
 6734 #?     (print-int32-buffered Stderr %eax)
 6735 #?     (write-buffered Stderr Newline)
 6736 #?     (flush Stderr)
 6737 $new-block-name:end:
 6738     # . reclaim locals
 6739     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 6740     81 0/subop/add %ecx 8/imm32  # slice
 6741     01/add-to %esp 1/r32/ecx
 6742     # . restore registers
 6743     5a/pop-to-edx
 6744     59/pop-to-ecx
 6745     58/pop-to-eax
 6746     # . epilogue
 6747     89/<- %esp 5/r32/ebp
 6748     5d/pop-to-ebp
 6749     c3/return
 6750 
 6751 == data
 6752 
 6753 # Global state added to each var record when parsing a function
 6754 Next-block-index:  # (addr int)
 6755     1/imm32
 6756 
 6757 == code
 6758 
 6759 check-no-tokens-left:  # line: (addr stream byte)
 6760     # . prologue
 6761     55/push-ebp
 6762     89/<- %ebp 4/r32/esp
 6763     # . save registers
 6764     50/push-eax
 6765     51/push-ecx
 6766     # var s/ecx: slice
 6767     68/push 0/imm32/end
 6768     68/push 0/imm32/start
 6769     89/<- %ecx 4/r32/esp
 6770     #
 6771     (next-mu-token *(ebp+8) %ecx)
 6772     # if slice-empty?(s) return
 6773     (slice-empty? %ecx)
 6774     3d/compare-eax-and 0/imm32/false
 6775     75/jump-if-!= $check-no-tokens-left:end/disp8
 6776     # if (slice-starts-with?(s, '#') return
 6777     # . eax = *s->start
 6778     8b/-> *edx 0/r32/eax
 6779     8a/copy-byte *eax 0/r32/AL
 6780     81 4/subop/and %eax 0xff/imm32
 6781     # . if (eax == '#') continue
 6782     3d/compare-eax-and 0x23/imm32/hash
 6783     74/jump-if-= $check-no-tokens-left:end/disp8
 6784     # abort
 6785     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 6786     (rewind-stream %ecx)
 6787     (write-stream 2 %ecx)
 6788     (write-buffered Stderr "'\n")
 6789     (flush Stderr)
 6790     # . syscall(exit, 1)
 6791     bb/copy-to-ebx  1/imm32
 6792     e8/call syscall_exit/disp32
 6793     # never gets here
 6794 $check-no-tokens-left:end:
 6795     # . reclaim locals
 6796     81 0/subop/add %esp 8/imm32
 6797     # . restore registers
 6798     59/pop-to-ecx
 6799     58/pop-to-eax
 6800     # . epilogue
 6801     89/<- %esp 5/r32/ebp
 6802     5d/pop-to-ebp
 6803     c3/return
 6804 
 6805 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)
 6806     # pseudocode:
 6807     #   var v: (handle var)
 6808     #   new-literal(name, v)
 6809     #   push(vars, {v, false})
 6810     #   parse-mu-block(in, vars, fn, out)
 6811     #   pop(vars)
 6812     #   out->tag = block
 6813     #   out->var = v
 6814     #
 6815     # . prologue
 6816     55/push-ebp
 6817     89/<- %ebp 4/r32/esp
 6818     # . save registers
 6819     50/push-eax
 6820     51/push-ecx
 6821     57/push-edi
 6822     # var v/ecx: (handle var)
 6823     68/push 0/imm32
 6824     68/push 0/imm32
 6825     89/<- %ecx 4/r32/esp
 6826     #
 6827     (new-literal Heap *(ebp+8) %ecx)
 6828     # push(vars, v)
 6829     (push *(ebp+0x10) *ecx)
 6830     (push *(ebp+0x10) *(ecx+4))
 6831     (push *(ebp+0x10) 0)  # false
 6832     #
 6833     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 6834     # pop v off vars
 6835     (pop *(ebp+0x10))  # => eax
 6836     (pop *(ebp+0x10))  # => eax
 6837     (pop *(ebp+0x10))  # => eax
 6838     # var out-addr/edi: (addr stmt) = lookup(*out)
 6839     8b/-> *(ebp+0x18) 7/r32/edi
 6840     (lookup *edi *(edi+4))  # => eax
 6841     89/<- %edi 0/r32/eax
 6842     # out-addr->tag = named-block
 6843     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 6844     # out-addr->var = v
 6845     8b/-> *ecx 0/r32/eax
 6846     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 6847     8b/-> *(ecx+4) 0/r32/eax
 6848     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 6849 $parse-mu-named-block:end:
 6850     # . reclaim locals
 6851     81 0/subop/add %esp 8/imm32
 6852     # . restore registers
 6853     5f/pop-to-edi
 6854     59/pop-to-ecx
 6855     58/pop-to-eax
 6856     # . epilogue
 6857     89/<- %esp 5/r32/ebp
 6858     5d/pop-to-ebp
 6859     c3/return
 6860 
 6861 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)
 6862     # . prologue
 6863     55/push-ebp
 6864     89/<- %ebp 4/r32/esp
 6865     # . save registers
 6866     50/push-eax
 6867     51/push-ecx
 6868     52/push-edx
 6869     57/push-edi
 6870     # edi = out
 6871     8b/-> *(ebp+0x10) 7/r32/edi
 6872     # var word-slice/ecx: slice
 6873     68/push 0/imm32/end
 6874     68/push 0/imm32/start
 6875     89/<- %ecx 4/r32/esp
 6876     # var v/edx: (handle var)
 6877     68/push 0/imm32
 6878     68/push 0/imm32
 6879     89/<- %edx 4/r32/esp
 6880     # v = parse-var-with-type(next-mu-token(line))
 6881     (next-mu-token *(ebp+8) %ecx)
 6882     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 6883     #
 6884     (push *(ebp+0xc) *edx)
 6885     (push *(ebp+0xc) *(edx+4))
 6886     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 6887     # either v has no register and there's no more to this line
 6888     (lookup *edx *(edx+4))  # => eax
 6889     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 6890     3d/compare-eax-and 0/imm32
 6891     {
 6892       75/jump-if-!= break/disp8
 6893       # TODO: disallow vars of type 'byte' on the stack
 6894       # ensure that there's nothing else on this line
 6895       (next-mu-token *(ebp+8) %ecx)
 6896       (slice-empty? %ecx)  # => eax
 6897       3d/compare-eax-and 0/imm32/false
 6898       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 6899       #
 6900       (new-var-def Heap  *edx *(edx+4)  %edi)
 6901       e9/jump $parse-mu-var-def:end/disp32
 6902     }
 6903     # or v has a register and there's more to this line
 6904     {
 6905       0f 84/jump-if-= break/disp32
 6906       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 6907       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 6908       # ensure that the next word is '<-'
 6909       (next-mu-token *(ebp+8) %ecx)
 6910       (slice-equal? %ecx "<-")  # => eax
 6911       3d/compare-eax-and 0/imm32/false
 6912       74/jump-if-= $parse-mu-var-def:error1/disp8
 6913       #
 6914       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 6915       (lookup *edi *(edi+4))  # => eax
 6916       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
 6917     }
 6918 $parse-mu-var-def:end:
 6919     # . reclaim locals
 6920     81 0/subop/add %esp 0x10/imm32
 6921     # . restore registers
 6922     5f/pop-to-edi
 6923     5a/pop-to-edx
 6924     59/pop-to-ecx
 6925     58/pop-to-eax
 6926     # . epilogue
 6927     89/<- %esp 5/r32/ebp
 6928     5d/pop-to-ebp
 6929     c3/return
 6930 
 6931 $parse-mu-var-def:error1:
 6932     (rewind-stream *(ebp+8))
 6933     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 6934     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 6935     (flush *(ebp+0x18))
 6936     (write-stream-data *(ebp+0x18) *(ebp+8))
 6937     (write-buffered *(ebp+0x18) "'\n")
 6938     (flush *(ebp+0x18))
 6939     (stop *(ebp+0x1c) 1)
 6940     # never gets here
 6941 
 6942 $parse-mu-var-def:error2:
 6943     (rewind-stream *(ebp+8))
 6944     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 6945     (write-buffered *(ebp+0x18) "fn ")
 6946     8b/-> *(ebp+0x14) 0/r32/eax
 6947     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 6948     (write-buffered *(ebp+0x18) %eax)
 6949     (write-buffered *(ebp+0x18) ": var ")
 6950     # var v-addr/eax: (addr var) = lookup(v)
 6951     (lookup *edx *(edx+4))  # => eax
 6952     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6953     (write-buffered *(ebp+0x18) %eax)
 6954     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 6955     (flush *(ebp+0x18))
 6956     (stop *(ebp+0x1c) 1)
 6957     # never gets here
 6958 
 6959 test-parse-mu-var-def:
 6960     # 'var n: int'
 6961     # . prologue
 6962     55/push-ebp
 6963     89/<- %ebp 4/r32/esp
 6964     # setup
 6965     (clear-stream _test-input-stream)
 6966     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 6967     # var out/esi: (handle stmt)
 6968     68/push 0/imm32
 6969     68/push 0/imm32
 6970     89/<- %esi 4/r32/esp
 6971     # var vars/ecx: (stack (addr var) 16)
 6972     81 5/subop/subtract %esp 0xc0/imm32
 6973     68/push 0xc0/imm32/size
 6974     68/push 0/imm32/top
 6975     89/<- %ecx 4/r32/esp
 6976     (clear-stack %ecx)
 6977     # convert
 6978     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 6979     # var out-addr/esi: (addr stmt)
 6980     (lookup *esi *(esi+4))  # => eax
 6981     89/<- %esi 0/r32/eax
 6982     #
 6983     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 6984     # var v/ecx: (addr var) = lookup(out->var)
 6985     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 6986     89/<- %ecx 0/r32/eax
 6987     # v->name
 6988     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6989     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 6990     # v->register
 6991     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 6992     # v->type == int
 6993     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6994     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 6995     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 6996     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 6997     # . epilogue
 6998     89/<- %esp 5/r32/ebp
 6999     5d/pop-to-ebp
 7000     c3/return
 7001 
 7002 test-parse-mu-reg-var-def:
 7003     # 'var n/eax: int <- copy 0'
 7004     # . prologue
 7005     55/push-ebp
 7006     89/<- %ebp 4/r32/esp
 7007     # setup
 7008     (clear-stream _test-input-stream)
 7009     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 7010     # var out/esi: (handle stmt)
 7011     68/push 0/imm32
 7012     68/push 0/imm32
 7013     89/<- %esi 4/r32/esp
 7014     # var vars/ecx: (stack (addr var) 16)
 7015     81 5/subop/subtract %esp 0xc0/imm32
 7016     68/push 0xc0/imm32/size
 7017     68/push 0/imm32/top
 7018     89/<- %ecx 4/r32/esp
 7019     (clear-stack %ecx)
 7020     # convert
 7021     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 7022     # var out-addr/esi: (addr stmt)
 7023     (lookup *esi *(esi+4))  # => eax
 7024     89/<- %esi 0/r32/eax
 7025     #
 7026     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 7027     # var v/ecx: (addr var) = lookup(out->outputs->value)
 7028     # . eax: (addr stmt-var) = lookup(out->outputs)
 7029     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 7030     # .
 7031     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 7032     # . eax: (addr var) = lookup(eax->value)
 7033     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7034     # . ecx = eax
 7035     89/<- %ecx 0/r32/eax
 7036     # v->name
 7037     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 7038     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 7039     # v->register
 7040     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 7041     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 7042     # v->type == int
 7043     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7044     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 7045     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 7046     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 7047     # . epilogue
 7048     89/<- %esp 5/r32/ebp
 7049     5d/pop-to-ebp
 7050     c3/return
 7051 
 7052 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)
 7053     # pseudocode:
 7054     #   var name: slice
 7055     #   allocate(Heap, Stmt-size, out)
 7056     #   var out-addr: (addr stmt) = lookup(*out)
 7057     #   out-addr->tag = stmt
 7058     #   if stmt-has-outputs?(line)
 7059     #     while true
 7060     #       name = next-mu-token(line)
 7061     #       if (name == '<-') break
 7062     #       assert(is-identifier?(name))
 7063     #       var v: (handle var) = lookup-or-define-var(name, vars, fn)  # regular stmts may define vars in fn outputs
 7064     #       out-addr->outputs = append(v, out-addr->outputs)
 7065     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 7066     #
 7067     # . prologue
 7068     55/push-ebp
 7069     89/<- %ebp 4/r32/esp
 7070     # . save registers
 7071     50/push-eax
 7072     51/push-ecx
 7073     52/push-edx
 7074     53/push-ebx
 7075     57/push-edi
 7076     # var name/ecx: slice
 7077     68/push 0/imm32/end
 7078     68/push 0/imm32/start
 7079     89/<- %ecx 4/r32/esp
 7080     # var is-deref?/edx: boolean = false
 7081     ba/copy-to-edx 0/imm32/false
 7082     # var v: (handle var)
 7083     68/push 0/imm32
 7084     68/push 0/imm32
 7085     89/<- %ebx 4/r32/esp
 7086     #
 7087     (allocate Heap *Stmt-size *(ebp+0x14))
 7088     # var out-addr/edi: (addr stmt) = lookup(*out)
 7089     8b/-> *(ebp+0x14) 7/r32/edi
 7090     (lookup *edi *(edi+4))  # => eax
 7091     89/<- %edi 0/r32/eax
 7092     # out-addr->tag = 1/stmt
 7093     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 7094     {
 7095       (stmt-has-outputs? *(ebp+8))
 7096       3d/compare-eax-and 0/imm32/false
 7097       0f 84/jump-if-= break/disp32
 7098       {
 7099 $parse-mu-stmt:read-outputs:
 7100         # name = next-mu-token(line)
 7101         (next-mu-token *(ebp+8) %ecx)
 7102         # if slice-empty?(word-slice) break
 7103         (slice-empty? %ecx)  # => eax
 7104         3d/compare-eax-and 0/imm32/false
 7105         0f 85/jump-if-!= break/disp32
 7106         # if (name == "<-") break
 7107         (slice-equal? %ecx "<-")  # => eax
 7108         3d/compare-eax-and 0/imm32/false
 7109         0f 85/jump-if-!= break/disp32
 7110         # is-deref? = false
 7111         ba/copy-to-edx 0/imm32/false
 7112         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 7113         8b/-> *ecx 0/r32/eax  # Slice-start
 7114         8a/copy-byte *eax 0/r32/AL
 7115         81 4/subop/and %eax 0xff/imm32
 7116         3d/compare-eax-and 0x2a/imm32/asterisk
 7117         {
 7118           75/jump-if-!= break/disp8
 7119           ff 0/subop/increment *ecx
 7120           ba/copy-to-edx 1/imm32/true
 7121         }
 7122         # assert(is-identifier?(name))
 7123         (is-identifier? %ecx)  # => eax
 7124         3d/compare-eax-and 0/imm32/false
 7125         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 7126         #
 7127         (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 7128         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 7129         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 7130         #
 7131         e9/jump loop/disp32
 7132       }
 7133     }
 7134     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
 7135 $parse-mu-stmt:end:
 7136     # . reclaim locals
 7137     81 0/subop/add %esp 0x10/imm32
 7138     # . restore registers
 7139     5f/pop-to-edi
 7140     5b/pop-to-ebx
 7141     5a/pop-to-edx
 7142     59/pop-to-ecx
 7143     58/pop-to-eax
 7144     # . epilogue
 7145     89/<- %esp 5/r32/ebp
 7146     5d/pop-to-ebp
 7147     c3/return
 7148 
 7149 $parse-mu-stmt:abort:
 7150     # error("invalid identifier '" name "'\n")
 7151     (write-buffered *(ebp+0x18) "invalid identifier '")
 7152     (write-slice-buffered *(ebp+0x18) %ecx)
 7153     (write-buffered *(ebp+0x18) "'\n")
 7154     (flush *(ebp+0x18))
 7155     (stop *(ebp+0x1c) 1)
 7156     # never gets here
 7157 
 7158 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7159     # pseudocode:
 7160     #   stmt->name = slice-to-string(next-mu-token(line))
 7161     #   while true
 7162     #     name = next-mu-token(line)
 7163     #     v = lookup-var-or-literal(name)
 7164     #     stmt->inouts = append(v, stmt->inouts)
 7165     #
 7166     # . prologue
 7167     55/push-ebp
 7168     89/<- %ebp 4/r32/esp
 7169     # . save registers
 7170     50/push-eax
 7171     51/push-ecx
 7172     52/push-edx
 7173     53/push-ebx
 7174     56/push-esi
 7175     57/push-edi
 7176     # edi = stmt
 7177     8b/-> *(ebp+8) 7/r32/edi
 7178     # var name/ecx: slice
 7179     68/push 0/imm32/end
 7180     68/push 0/imm32/start
 7181     89/<- %ecx 4/r32/esp
 7182     # var is-deref?/edx: boolean = false
 7183     ba/copy-to-edx 0/imm32/false
 7184     # var v/esi: (handle var)
 7185     68/push 0/imm32
 7186     68/push 0/imm32
 7187     89/<- %esi 4/r32/esp
 7188 $add-operation-and-inputs-to-stmt:read-operation:
 7189     (next-mu-token *(ebp+0xc) %ecx)
 7190     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 7191     (slice-to-string Heap %ecx %eax)
 7192     # var is-get?/ebx: boolean = (name == "get")
 7193     (slice-equal? %ecx "get")  # => eax
 7194     89/<- %ebx 0/r32/eax
 7195     {
 7196 $add-operation-and-inputs-to-stmt:read-inouts:
 7197       # name = next-mu-token(line)
 7198       (next-mu-token *(ebp+0xc) %ecx)
 7199       # if slice-empty?(word-slice) break
 7200       (slice-empty? %ecx)  # => eax
 7201       3d/compare-eax-and 0/imm32/false
 7202       0f 85/jump-if-!= break/disp32
 7203       # if (name == "<-") abort
 7204       (slice-equal? %ecx "<-")
 7205       3d/compare-eax-and 0/imm32/false
 7206       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 7207       # if (is-get? && second operand) lookup or create offset
 7208       {
 7209         81 7/subop/compare %ebx 0/imm32/false
 7210         74/jump-if-= break/disp8
 7211         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 7212         3d/compare-eax-and 0/imm32
 7213         74/jump-if-= break/disp8
 7214         (lookup-or-create-constant %eax %ecx %esi)
 7215 #?         (lookup *esi *(esi+4))
 7216 #?         (write-buffered Stderr "creating new output var ")
 7217 #?         (print-int32-buffered Stderr %eax)
 7218 #?         (write-buffered Stderr " for field called ")
 7219 #?         (write-slice-buffered Stderr %ecx)
 7220 #?         (write-buffered Stderr "; var name ")
 7221 #?         (lookup *eax *(eax+4))  # Var-name
 7222 #?         (write-buffered Stderr %eax)
 7223 #?         (write-buffered Stderr Newline)
 7224 #?         (flush Stderr)
 7225         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 7226       }
 7227       # is-deref? = false
 7228       ba/copy-to-edx 0/imm32/false
 7229       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 7230       8b/-> *ecx 0/r32/eax  # Slice-start
 7231       8a/copy-byte *eax 0/r32/AL
 7232       81 4/subop/and %eax 0xff/imm32
 7233       3d/compare-eax-and 0x2a/imm32/asterisk
 7234       {
 7235         75/jump-if-!= break/disp8
 7236 $add-operation-and-inputs-to-stmt:inout-is-deref:
 7237         ff 0/subop/increment *ecx
 7238         ba/copy-to-edx 1/imm32/true
 7239       }
 7240       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18))
 7241 $add-operation-and-inputs-to-stmt:save-var:
 7242       8d/copy-address *(edi+0xc) 0/r32/eax
 7243       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 7244       #
 7245       e9/jump loop/disp32
 7246     }
 7247 $add-operation-and-inputs-to-stmt:end:
 7248     # . reclaim locals
 7249     81 0/subop/add %esp 0x10/imm32
 7250     # . restore registers
 7251     5f/pop-to-edi
 7252     5e/pop-to-esi
 7253     5b/pop-to-ebx
 7254     5a/pop-to-edx
 7255     59/pop-to-ecx
 7256     58/pop-to-eax
 7257     # . epilogue
 7258     89/<- %esp 5/r32/ebp
 7259     5d/pop-to-ebp
 7260     c3/return
 7261 
 7262 $add-operation-and-inputs-to-stmt:abort:
 7263     # error("invalid statement '" line "'\n")
 7264     (rewind-stream *(ebp+8))
 7265     (write-buffered *(ebp+0x14) "invalid identifier '")
 7266     (write-stream-data *(ebp+0x14) *(ebp+8))
 7267     (write-buffered *(ebp+0x14) "'\n")
 7268     (flush *(ebp+0x14))
 7269     (stop *(ebp+0x18) 1)
 7270     # never gets here
 7271 
 7272 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 7273     # . prologue
 7274     55/push-ebp
 7275     89/<- %ebp 4/r32/esp
 7276     # . save registers
 7277     51/push-ecx
 7278     # var word-slice/ecx: slice
 7279     68/push 0/imm32/end
 7280     68/push 0/imm32/start
 7281     89/<- %ecx 4/r32/esp
 7282     # result = false
 7283     b8/copy-to-eax 0/imm32/false
 7284     (rewind-stream *(ebp+8))
 7285     {
 7286       (next-mu-token *(ebp+8) %ecx)
 7287       # if slice-empty?(word-slice) break
 7288       (slice-empty? %ecx)
 7289       3d/compare-eax-and 0/imm32/false
 7290       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 7291       0f 85/jump-if-!= break/disp32
 7292       # if slice-starts-with?(word-slice, '#') break
 7293       # . eax = *word-slice->start
 7294       8b/-> *ecx 0/r32/eax
 7295       8a/copy-byte *eax 0/r32/AL
 7296       81 4/subop/and %eax 0xff/imm32
 7297       # . if (eax == '#') break
 7298       3d/compare-eax-and 0x23/imm32/hash
 7299       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 7300       0f 84/jump-if-= break/disp32
 7301       # if slice-equal?(word-slice, '<-') return true
 7302       (slice-equal? %ecx "<-")
 7303       3d/compare-eax-and 0/imm32/false
 7304       74/jump-if-= loop/disp8
 7305       b8/copy-to-eax 1/imm32/true
 7306     }
 7307 $stmt-has-outputs:end:
 7308     (rewind-stream *(ebp+8))
 7309     # . reclaim locals
 7310     81 0/subop/add %esp 8/imm32
 7311     # . restore registers
 7312     59/pop-to-ecx
 7313     # . epilogue
 7314     89/<- %esp 5/r32/ebp
 7315     5d/pop-to-ebp
 7316     c3/return
 7317 
 7318 # if 'name' starts with a digit, create a new literal var for it
 7319 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 7320 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7321     # . prologue
 7322     55/push-ebp
 7323     89/<- %ebp 4/r32/esp
 7324     # . save registers
 7325     50/push-eax
 7326     51/push-ecx
 7327     56/push-esi
 7328     # esi = name
 7329     8b/-> *(ebp+8) 6/r32/esi
 7330     # if slice-empty?(name) abort
 7331     (slice-empty? %esi)  # => eax
 7332     3d/compare-eax-and 0/imm32/false
 7333     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 7334     # var c/ecx: byte = *name->start
 7335     8b/-> *esi 1/r32/ecx
 7336     8a/copy-byte *ecx 1/r32/CL
 7337     81 4/subop/and %ecx 0xff/imm32
 7338     # if is-decimal-digit?(c) return new var(name)
 7339     {
 7340       (is-decimal-digit? %ecx)  # => eax
 7341       3d/compare-eax-and 0/imm32/false
 7342       74/jump-if-= break/disp8
 7343 $lookup-var-or-literal:literal:
 7344       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 7345       eb/jump $lookup-var-or-literal:end/disp8
 7346     }
 7347     # else if (c == '"') return new var(name)
 7348     {
 7349       81 7/subop/compare %ecx 0x22/imm32/dquote
 7350       75/jump-if-!= break/disp8
 7351 $lookup-var-or-literal:literal-string:
 7352       (new-literal Heap %esi *(ebp+0x10))
 7353       eb/jump $lookup-var-or-literal:end/disp8
 7354     }
 7355     # otherwise return lookup-var(name, vars)
 7356     {
 7357 $lookup-var-or-literal:var:
 7358       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 7359     }
 7360 $lookup-var-or-literal:end:
 7361     # . restore registers
 7362     5e/pop-to-esi
 7363     59/pop-to-ecx
 7364     58/pop-to-eax
 7365     # . epilogue
 7366     89/<- %esp 5/r32/ebp
 7367     5d/pop-to-ebp
 7368     c3/return
 7369 
 7370 $lookup-var-or-literal:abort:
 7371     (write-buffered *(ebp+0x14) "empty variable!")
 7372     (flush *(ebp+0x14))
 7373     (stop *(ebp+0x18) 1)
 7374     # never gets here
 7375 
 7376 # return first 'name' from the top (back) of 'vars' and abort if not found
 7377 lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7378     # . prologue
 7379     55/push-ebp
 7380     89/<- %ebp 4/r32/esp
 7381     # . save registers
 7382     50/push-eax
 7383     #
 7384     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 7385     # if (*out == 0) abort
 7386     8b/-> *(ebp+0x10) 0/r32/eax
 7387     81 7/subop/compare *eax 0/imm32
 7388     74/jump-if-= $lookup-var:abort/disp8
 7389 $lookup-var:end:
 7390     # . restore registers
 7391     58/pop-to-eax
 7392     # . epilogue
 7393     89/<- %esp 5/r32/ebp
 7394     5d/pop-to-ebp
 7395     c3/return
 7396 
 7397 $lookup-var:abort:
 7398     (write-buffered *(ebp+0x14) "unknown variable '")
 7399     (write-slice-buffered *(ebp+0x14) *(ebp+8))
 7400     (write-buffered *(ebp+0x14) "'\n")
 7401     (flush *(ebp+0x14))
 7402     (stop *(ebp+0x18) 1)
 7403     # never gets here
 7404 
 7405 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 7406 lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7407     # pseudocode:
 7408     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 7409     #   var min = vars->data
 7410     #   while curr >= min
 7411     #     var v: (handle var) = *curr
 7412     #     if v->name == name
 7413     #       return
 7414     #     curr -= 12
 7415     #
 7416     # . prologue
 7417     55/push-ebp
 7418     89/<- %ebp 4/r32/esp
 7419     # . save registers
 7420     50/push-eax
 7421     51/push-ecx
 7422     52/push-edx
 7423     53/push-ebx
 7424     56/push-esi
 7425     # clear out
 7426     (zero-out *(ebp+0x10) *Handle-size)
 7427     # esi = vars
 7428     8b/-> *(ebp+0xc) 6/r32/esi
 7429     # ebx = vars->top
 7430     8b/-> *esi 3/r32/ebx
 7431     # if (vars->top > vars->size) abort
 7432     3b/compare<- *(esi+4) 0/r32/eax
 7433     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 7434     # var min/edx: (addr handle var) = vars->data
 7435     8d/copy-address *(esi+8) 2/r32/edx
 7436     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 7437     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 7438     {
 7439       # if (curr < min) return
 7440       39/compare %ebx 2/r32/edx
 7441       0f 82/jump-if-addr< break/disp32
 7442       # var v/ecx: (addr var) = lookup(*curr)
 7443       (lookup *ebx *(ebx+4))  # => eax
 7444       89/<- %ecx 0/r32/eax
 7445       # var vn/eax: (addr array byte) = lookup(v->name)
 7446       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 7447       # if (vn == name) return curr
 7448       (slice-equal? *(ebp+8) %eax)  # => eax
 7449       3d/compare-eax-and 0/imm32/false
 7450       {
 7451         74/jump-if-= break/disp8
 7452         # esi = out
 7453         8b/-> *(ebp+0x10) 6/r32/esi
 7454         # *out = *curr
 7455         8b/-> *ebx 0/r32/eax
 7456         89/<- *esi 0/r32/eax
 7457         8b/-> *(ebx+4) 0/r32/eax
 7458         89/<- *(esi+4) 0/r32/eax
 7459         # return
 7460         eb/jump $lookup-var-helper:end/disp8
 7461       }
 7462       # curr -= 12
 7463       81 5/subop/subtract %ebx 0xc/imm32
 7464       e9/jump loop/disp32
 7465     }
 7466 $lookup-var-helper:end:
 7467     # . restore registers
 7468     5e/pop-to-esi
 7469     5b/pop-to-ebx
 7470     5a/pop-to-edx
 7471     59/pop-to-ecx
 7472     58/pop-to-eax
 7473     # . epilogue
 7474     89/<- %esp 5/r32/ebp
 7475     5d/pop-to-ebp
 7476     c3/return
 7477 
 7478 $lookup-var-helper:error1:
 7479     (write-buffered *(ebp+0x14) "malformed stack when looking up '")
 7480     (write-slice-buffered *(ebp+0x14) *(ebp+8))
 7481     (write-buffered *(ebp+0x14) "'\n")
 7482     (flush *(ebp+0x14))
 7483     (stop *(ebp+0x18) 1)
 7484     # never gets here
 7485 
 7486 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 7487 lookup-or-define-var:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7488     # . prologue
 7489     55/push-ebp
 7490     89/<- %ebp 4/r32/esp
 7491     # . save registers
 7492     50/push-eax
 7493     #
 7494     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
 7495     {
 7496       # if (out != 0) return
 7497       8b/-> *(ebp+0x14) 0/r32/eax
 7498       81 7/subop/compare *eax 0/imm32
 7499       75/jump-if-!= break/disp8
 7500       # if name is one of fn's outputs, return it
 7501       {
 7502         (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 7503         8b/-> *(ebp+0x14) 0/r32/eax
 7504         81 7/subop/compare *eax 0/imm32
 7505         # otherwise abort
 7506         0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 7507         # update vars
 7508         (push *(ebp+0xc) *eax)
 7509         (push *(ebp+0xc) *(eax+4))
 7510         (push *(ebp+0xc) 0)  # never spill fn-outputs
 7511       }
 7512     }
 7513 $lookup-or-define-var:end:
 7514     # . restore registers
 7515     58/pop-to-eax
 7516     # . epilogue
 7517     89/<- %esp 5/r32/ebp
 7518     5d/pop-to-ebp
 7519     c3/return
 7520 
 7521 $lookup-or-define-var:abort:
 7522     (write-buffered *(ebp+0x18) "unknown variable '")
 7523     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 7524     (write-buffered *(ebp+0x18) "'\n")
 7525     (flush *(ebp+0x18))
 7526     (stop *(ebp+0x1c) 1)
 7527     # never gets here
 7528 
 7529 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 7530     # . prologue
 7531     55/push-ebp
 7532     89/<- %ebp 4/r32/esp
 7533     # . save registers
 7534     50/push-eax
 7535     51/push-ecx
 7536     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 7537     8b/-> *(ebp+8) 1/r32/ecx
 7538     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 7539     89/<- %ecx 0/r32/eax
 7540     # while curr != null
 7541     {
 7542       81 7/subop/compare %ecx 0/imm32
 7543       74/jump-if-= break/disp8
 7544       # var v/eax: (addr var) = lookup(curr->value)
 7545       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 7546       # var s/eax: (addr array byte) = lookup(v->name)
 7547       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7548       # if (s == name) return curr->value
 7549       (slice-equal? *(ebp+0xc) %eax)  # => eax
 7550       3d/compare-eax-and 0/imm32/false
 7551       {
 7552         74/jump-if-= break/disp8
 7553         # var edi = out
 7554         57/push-edi
 7555         8b/-> *(ebp+0x10) 7/r32/edi
 7556         # *out = curr->value
 7557         8b/-> *ecx 0/r32/eax
 7558         89/<- *edi 0/r32/eax
 7559         8b/-> *(ecx+4) 0/r32/eax
 7560         89/<- *(edi+4) 0/r32/eax
 7561         #
 7562         5f/pop-to-edi
 7563         eb/jump $find-in-function-outputs:end/disp8
 7564       }
 7565       # curr = curr->next
 7566       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 7567       89/<- %ecx 0/r32/eax
 7568       #
 7569       eb/jump loop/disp8
 7570     }
 7571     b8/copy-to-eax 0/imm32
 7572 $find-in-function-outputs:end:
 7573     # . restore registers
 7574     59/pop-to-ecx
 7575     58/pop-to-eax
 7576     # . epilogue
 7577     89/<- %esp 5/r32/ebp
 7578     5d/pop-to-ebp
 7579     c3/return
 7580 
 7581 test-parse-mu-stmt:
 7582     # . prologue
 7583     55/push-ebp
 7584     89/<- %ebp 4/r32/esp
 7585     # setup
 7586     (clear-stream _test-input-stream)
 7587     (write _test-input-stream "increment n\n")
 7588     # var vars/ecx: (stack (addr var) 16)
 7589     81 5/subop/subtract %esp 0xc0/imm32
 7590     68/push 0xc0/imm32/size
 7591     68/push 0/imm32/top
 7592     89/<- %ecx 4/r32/esp
 7593     (clear-stack %ecx)
 7594     # var v/edx: (handle var)
 7595     68/push 0/imm32
 7596     68/push 0/imm32
 7597     89/<- %edx 4/r32/esp
 7598     # var s/eax: (handle array byte)
 7599     68/push 0/imm32
 7600     68/push 0/imm32
 7601     89/<- %eax 4/r32/esp
 7602     # v = new var("n")
 7603     (copy-array Heap "n" %eax)
 7604     (new-var Heap *eax *(eax+4) %edx)
 7605     #
 7606     (push %ecx *edx)
 7607     (push %ecx *(edx+4))
 7608     (push %ecx 0)
 7609     # var out/eax: (handle stmt)
 7610     68/push 0/imm32
 7611     68/push 0/imm32
 7612     89/<- %eax 4/r32/esp
 7613     # convert
 7614     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 7615     # var out-addr/edx: (addr stmt) = lookup(*out)
 7616     (lookup *eax *(eax+4))  # => eax
 7617     89/<- %edx 0/r32/eax
 7618     # out->tag
 7619     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 7620     # out->operation
 7621     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 7622     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 7623     # out->inouts->value->name
 7624     # . eax = out->inouts
 7625     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 7626     # . eax = out->inouts->value
 7627     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7628     # . eax = out->inouts->value->name
 7629     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7630     # .
 7631     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 7632     # . epilogue
 7633     89/<- %esp 5/r32/ebp
 7634     5d/pop-to-ebp
 7635     c3/return
 7636 
 7637 test-parse-mu-stmt-with-comma:
 7638     # . prologue
 7639     55/push-ebp
 7640     89/<- %ebp 4/r32/esp
 7641     # setup
 7642     (clear-stream _test-input-stream)
 7643     (write _test-input-stream "copy-to n, 3\n")
 7644     # var vars/ecx: (stack (addr var) 16)
 7645     81 5/subop/subtract %esp 0xc0/imm32
 7646     68/push 0xc0/imm32/size
 7647     68/push 0/imm32/top
 7648     89/<- %ecx 4/r32/esp
 7649     (clear-stack %ecx)
 7650     # var v/edx: (handle var)
 7651     68/push 0/imm32
 7652     68/push 0/imm32
 7653     89/<- %edx 4/r32/esp
 7654     # var s/eax: (handle array byte)
 7655     68/push 0/imm32
 7656     68/push 0/imm32
 7657     89/<- %eax 4/r32/esp
 7658     # v = new var("n")
 7659     (copy-array Heap "n" %eax)
 7660     (new-var Heap *eax *(eax+4) %edx)
 7661     #
 7662     (push %ecx *edx)
 7663     (push %ecx *(edx+4))
 7664     (push %ecx 0)
 7665     # var out/eax: (handle stmt)
 7666     68/push 0/imm32
 7667     68/push 0/imm32
 7668     89/<- %eax 4/r32/esp
 7669     # convert
 7670     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 7671     # var out-addr/edx: (addr stmt) = lookup(*out)
 7672     (lookup *eax *(eax+4))  # => eax
 7673     89/<- %edx 0/r32/eax
 7674     # out->tag
 7675     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 7676     # out->operation
 7677     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 7678     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 7679     # out->inouts->value->name
 7680     # . eax = out->inouts
 7681     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 7682     # . eax = out->inouts->value
 7683     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7684     # . eax = out->inouts->value->name
 7685     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 7686     # .
 7687     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 7688     # . epilogue
 7689     89/<- %esp 5/r32/ebp
 7690     5d/pop-to-ebp
 7691     c3/return
 7692 
 7693 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 7694     # . prologue
 7695     55/push-ebp
 7696     89/<- %ebp 4/r32/esp
 7697     # . save registers
 7698     50/push-eax
 7699     51/push-ecx
 7700     # ecx = out
 7701     8b/-> *(ebp+0x14) 1/r32/ecx
 7702     #
 7703     (allocate *(ebp+8) *Var-size %ecx)
 7704     # var out-addr/eax: (addr var)
 7705     (lookup *ecx *(ecx+4))  # => eax
 7706     # out-addr->name = name
 7707     8b/-> *(ebp+0xc) 1/r32/ecx
 7708     89/<- *eax 1/r32/ecx  # Var-name
 7709     8b/-> *(ebp+0x10) 1/r32/ecx
 7710     89/<- *(eax+4) 1/r32/ecx  # Var-name
 7711 #?     (write-buffered Stderr "var ")
 7712 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 7713 #?     (write-buffered Stderr %eax)
 7714 #?     (write-buffered Stderr " at ")
 7715 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 7716 #?     (lookup *ecx *(ecx+4))  # => eax
 7717 #?     (print-int32-buffered Stderr %eax)
 7718 #?     (write-buffered Stderr Newline)
 7719 #?     (flush Stderr)
 7720 $new-var:end:
 7721     # . restore registers
 7722     59/pop-to-ecx
 7723     58/pop-to-eax
 7724     # . epilogue
 7725     89/<- %esp 5/r32/ebp
 7726     5d/pop-to-ebp
 7727     c3/return
 7728 
 7729 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7730     # . prologue
 7731     55/push-ebp
 7732     89/<- %ebp 4/r32/esp
 7733     # . save registers
 7734     50/push-eax
 7735     51/push-ecx
 7736     # if (!is-hex-int?(name)) abort
 7737     (is-hex-int? *(ebp+0xc))  # => eax
 7738     3d/compare-eax-and 0/imm32/false
 7739     0f 84/jump-if-= $new-literal-integer:abort/disp32
 7740     # out = new var(s)
 7741     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 7742     # var out-addr/ecx: (addr var) = lookup(*out)
 7743     8b/-> *(ebp+0x10) 0/r32/eax
 7744     (lookup *eax *(eax+4))  # => eax
 7745     89/<- %ecx 0/r32/eax
 7746     # out-addr->type = new tree()
 7747     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 7748     (allocate *(ebp+8) *Tree-size %eax)
 7749     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7750     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 7751     # nothing else to do; default type is 'literal'
 7752 $new-literal-integer:end:
 7753     # . reclaim locals
 7754     81 0/subop/add %esp 8/imm32
 7755     # . restore registers
 7756     59/pop-to-ecx
 7757     58/pop-to-eax
 7758     # . epilogue
 7759     89/<- %esp 5/r32/ebp
 7760     5d/pop-to-ebp
 7761     c3/return
 7762 
 7763 $new-literal-integer:abort:
 7764     (write-buffered *(ebp+0x14) "variable cannot begin with a digit '")
 7765     (write-slice-buffered *(ebp+0x14) *(ebp+0xc))
 7766     (write-buffered *(ebp+0x14) "'\n")
 7767     (flush *(ebp+0x14))
 7768     (stop *(ebp+0x18) 1)
 7769     # never gets here
 7770 
 7771 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 7772     # . prologue
 7773     55/push-ebp
 7774     89/<- %ebp 4/r32/esp
 7775     # . save registers
 7776     50/push-eax
 7777     51/push-ecx
 7778     # var s/ecx: (handle array byte)
 7779     68/push 0/imm32
 7780     68/push 0/imm32
 7781     89/<- %ecx 4/r32/esp
 7782     # s = slice-to-string(name)
 7783     (slice-to-string Heap *(ebp+0xc) %ecx)
 7784     # allocate to out
 7785     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 7786     # var out-addr/ecx: (addr var) = lookup(*out)
 7787     8b/-> *(ebp+0x10) 1/r32/ecx
 7788     (lookup *ecx *(ecx+4))  # => eax
 7789     89/<- %ecx 0/r32/eax
 7790     # out-addr->type/eax = new type
 7791     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 7792     (allocate *(ebp+8) *Tree-size %eax)
 7793     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7794     # nothing else to do; default type is 'literal'
 7795     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 7796 $new-literal:end:
 7797     # . reclaim locals
 7798     81 0/subop/add %esp 8/imm32
 7799     # . restore registers
 7800     59/pop-to-ecx
 7801     58/pop-to-eax
 7802     # . epilogue
 7803     89/<- %esp 5/r32/ebp
 7804     5d/pop-to-ebp
 7805     c3/return
 7806 
 7807 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 7808     # . prologue
 7809     55/push-ebp
 7810     89/<- %ebp 4/r32/esp
 7811     # . save registers
 7812     51/push-ecx
 7813     # var tmp/ecx: (handle array byte)
 7814     68/push 0/imm32
 7815     68/push 0/imm32
 7816     89/<- %ecx 4/r32/esp
 7817     # tmp = slice-to-string(name)
 7818     (slice-to-string Heap *(ebp+0xc) %ecx)
 7819     # out = new-var(tmp)
 7820     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 7821 $new-var-from-slice:end:
 7822     # . reclaim locals
 7823     81 0/subop/add %esp 8/imm32
 7824     # . restore registers
 7825     59/pop-to-ecx
 7826     # . epilogue
 7827     89/<- %esp 5/r32/ebp
 7828     5d/pop-to-ebp
 7829     c3/return
 7830 
 7831 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 7832     # . prologue
 7833     55/push-ebp
 7834     89/<- %ebp 4/r32/esp
 7835     # . save registers
 7836     50/push-eax
 7837     51/push-ecx
 7838     #
 7839     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 7840     # var out-addr/eax: (addr stmt) = lookup(*out)
 7841     8b/-> *(ebp+0x14) 0/r32/eax
 7842     (lookup *eax *(eax+4))  # => eax
 7843     # out-addr->tag = stmt
 7844     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 7845     # result->var = var
 7846     8b/-> *(ebp+0xc) 1/r32/ecx
 7847     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 7848     8b/-> *(ebp+0x10) 1/r32/ecx
 7849     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 7850 $new-var-def:end:
 7851     # . restore registers
 7852     59/pop-to-ecx
 7853     58/pop-to-eax
 7854     # . epilogue
 7855     89/<- %esp 5/r32/ebp
 7856     5d/pop-to-ebp
 7857     c3/return
 7858 
 7859 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 7860     # . prologue
 7861     55/push-ebp
 7862     89/<- %ebp 4/r32/esp
 7863     # . save registers
 7864     50/push-eax
 7865     # eax = out
 7866     8b/-> *(ebp+0x14) 0/r32/eax
 7867     #
 7868     (allocate *(ebp+8) *Stmt-size %eax)
 7869     # var out-addr/eax: (addr stmt) = lookup(*out)
 7870     (lookup *eax *(eax+4))  # => eax
 7871     # set tag
 7872     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 7873     # set output
 7874     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 7875     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 7876 $new-reg-var-def:end:
 7877     # . restore registers
 7878     58/pop-to-eax
 7879     # . epilogue
 7880     89/<- %esp 5/r32/ebp
 7881     5d/pop-to-ebp
 7882     c3/return
 7883 
 7884 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 7885     # . prologue
 7886     55/push-ebp
 7887     89/<- %ebp 4/r32/esp
 7888     # . save registers
 7889     50/push-eax
 7890     51/push-ecx
 7891     57/push-edi
 7892     # edi = out
 7893     8b/-> *(ebp+0x1c) 7/r32/edi
 7894     # *out = new list
 7895     (allocate *(ebp+8) *List-size %edi)
 7896     # var out-addr/edi: (addr list _type) = lookup(*out)
 7897     (lookup *edi *(edi+4))  # => eax
 7898     89/<- %edi 0/r32/eax
 7899     # out-addr->value = value
 7900     8b/-> *(ebp+0xc) 0/r32/eax
 7901     89/<- *edi 0/r32/eax  # List-value
 7902     8b/-> *(ebp+0x10) 0/r32/eax
 7903     89/<- *(edi+4) 0/r32/eax  # List-value
 7904     # if (list == null) return
 7905     81 7/subop/compare *(ebp+0x14) 0/imm32
 7906     74/jump-if-= $append-list:end/disp8
 7907     # otherwise append
 7908 $append-list:non-empty-list:
 7909     # var curr/eax: (addr list _type) = lookup(list)
 7910     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 7911     # while (curr->next != null) curr = curr->next
 7912     {
 7913       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 7914       74/jump-if-= break/disp8
 7915       # curr = lookup(curr->next)
 7916       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 7917       #
 7918       eb/jump loop/disp8
 7919     }
 7920     # edi = out
 7921     8b/-> *(ebp+0x1c) 7/r32/edi
 7922     # curr->next = out
 7923     8b/-> *edi 1/r32/ecx
 7924     89/<- *(eax+8) 1/r32/ecx  # List-next
 7925     8b/-> *(edi+4) 1/r32/ecx
 7926     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 7927     # out = list
 7928     8b/-> *(ebp+0x14) 1/r32/ecx
 7929     89/<- *edi 1/r32/ecx
 7930     8b/-> *(ebp+0x18) 1/r32/ecx
 7931     89/<- *(edi+4) 1/r32/ecx
 7932 $append-list:end:
 7933     # . restore registers
 7934     5f/pop-to-edi
 7935     59/pop-to-ecx
 7936     58/pop-to-eax
 7937     # . epilogue
 7938     89/<- %esp 5/r32/ebp
 7939     5d/pop-to-ebp
 7940     c3/return
 7941 
 7942 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 7943     # . prologue
 7944     55/push-ebp
 7945     89/<- %ebp 4/r32/esp
 7946     # . save registers
 7947     50/push-eax
 7948     51/push-ecx
 7949     57/push-edi
 7950     # edi = out
 7951     8b/-> *(ebp+0x20) 7/r32/edi
 7952     # out = new stmt-var
 7953     (allocate *(ebp+8) *Stmt-var-size %edi)
 7954     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 7955     (lookup *edi *(edi+4))  # => eax
 7956     89/<- %ecx 0/r32/eax
 7957     # out-addr->value = v
 7958     8b/-> *(ebp+0xc) 0/r32/eax
 7959     89/<- *ecx 0/r32/eax  # Stmt-var-value
 7960     8b/-> *(ebp+0x10) 0/r32/eax
 7961     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 7962     # out-addr->is-deref? = is-deref?
 7963     8b/-> *(ebp+0x1c) 0/r32/eax
 7964     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 7965     # if (vars == null) return result
 7966     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 7967     74/jump-if-= $append-stmt-var:end/disp8
 7968     # otherwise append
 7969     # var curr/eax: (addr stmt-var) = lookup(vars)
 7970     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 7971     # while (curr->next != null) curr = curr->next
 7972     {
 7973       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 7974       74/jump-if-= break/disp8
 7975       # curr = lookup(curr->next)
 7976       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 7977       #
 7978       eb/jump loop/disp8
 7979     }
 7980     # curr->next = out
 7981     8b/-> *edi 1/r32/ecx
 7982     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 7983     8b/-> *(edi+4) 1/r32/ecx
 7984     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 7985     # out = vars
 7986     8b/-> *(ebp+0x14) 1/r32/ecx
 7987     89/<- *edi 1/r32/ecx
 7988     8b/-> *(ebp+0x18) 1/r32/ecx
 7989     89/<- *(edi+4) 1/r32/ecx
 7990 $append-stmt-var:end:
 7991     # . restore registers
 7992     5f/pop-to-edi
 7993     59/pop-to-ecx
 7994     58/pop-to-eax
 7995     # . epilogue
 7996     89/<- %esp 5/r32/ebp
 7997     5d/pop-to-ebp
 7998     c3/return
 7999 
 8000 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 8001     # . prologue
 8002     55/push-ebp
 8003     89/<- %ebp 4/r32/esp
 8004     # . save registers
 8005     50/push-eax
 8006     56/push-esi
 8007     # esi = block
 8008     8b/-> *(ebp+0xc) 6/r32/esi
 8009     # block->stmts = append(x, block->stmts)
 8010     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 8011     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 8012 $append-to-block:end:
 8013     # . restore registers
 8014     5e/pop-to-esi
 8015     58/pop-to-eax
 8016     # . epilogue
 8017     89/<- %esp 5/r32/ebp
 8018     5d/pop-to-ebp
 8019     c3/return
 8020 
 8021 ## Parsing types
 8022 # We need to create metadata on user-defined types, and we need to use this
 8023 # metadata as we parse instructions.
 8024 # However, we also want to allow types to be used before their definitions.
 8025 # This means we can't ever assume any type data structures exist.
 8026 
 8027 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 8028     # . prologue
 8029     55/push-ebp
 8030     89/<- %ebp 4/r32/esp
 8031     # . save registers
 8032     50/push-eax
 8033     56/push-esi
 8034     # var container-type/esi: type-id
 8035     (container-type *(ebp+8))  # => eax
 8036     89/<- %esi 0/r32/eax
 8037     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 8038     68/push 0/imm32
 8039     68/push 0/imm32
 8040     89/<- %eax 4/r32/esp
 8041     (find-or-create-typeinfo %esi %eax)
 8042     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 8043     (lookup *eax *(eax+4))  # => eax
 8044     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 8045 #?     (write-buffered Stderr "constant: ")
 8046 #?     (write-slice-buffered Stderr *(ebp+0xc))
 8047 #?     (write-buffered Stderr Newline)
 8048 #?     (flush Stderr)
 8049     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 8050 #?     8b/-> *(ebp+0x10) 0/r32/eax
 8051 #?     (write-buffered Stderr "@")
 8052 #?     (lookup *eax *(eax+4))
 8053 #?     (print-int32-buffered Stderr %eax)
 8054 #?     (lookup *eax *(eax+4))
 8055 #?     (write-buffered Stderr %eax)
 8056 #?     (write-buffered Stderr Newline)
 8057 #?     (flush Stderr)
 8058 #?     (write-buffered Stderr "offset: ")
 8059 #?     8b/-> *(eax+0x14) 0/r32/eax
 8060 #?     (print-int32-buffered Stderr %eax)
 8061 #?     (write-buffered Stderr Newline)
 8062 #?     (flush Stderr)
 8063 $lookup-or-create-constant:end:
 8064     # . reclaim locals
 8065     81 0/subop/add %esp 8/imm32
 8066     # . restore registers
 8067     5e/pop-to-esi
 8068     58/pop-to-eax
 8069     # . epilogue
 8070     89/<- %esp 5/r32/ebp
 8071     5d/pop-to-ebp
 8072     c3/return
 8073 
 8074 # if addr var:
 8075 #   container->var->type->right->left->value
 8076 # otherwise
 8077 #   container->var->type->value
 8078 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 8079     # . prologue
 8080     55/push-ebp
 8081     89/<- %ebp 4/r32/esp
 8082     #
 8083     8b/-> *(ebp+8) 0/r32/eax
 8084     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8085     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 8086     {
 8087       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 8088       74/jump-if-= break/disp8
 8089       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 8090       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 8091     }
 8092     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 8093 $container-type:end:
 8094     # . epilogue
 8095     89/<- %esp 5/r32/ebp
 8096     5d/pop-to-ebp
 8097     c3/return
 8098 
 8099 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 8100     # . prologue
 8101     55/push-ebp
 8102     89/<- %ebp 4/r32/esp
 8103     # . save registers
 8104     50/push-eax
 8105     51/push-ecx
 8106     52/push-edx
 8107     57/push-edi
 8108     # edi = out
 8109     8b/-> *(ebp+0xc) 7/r32/edi
 8110     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 8111     68/push 0/imm32
 8112     68/push 0/imm32
 8113     89/<- %ecx 4/r32/esp
 8114     # find-typeinfo(t, out)
 8115     (find-typeinfo *(ebp+8) %edi)
 8116     {
 8117       # if (*out != 0) break
 8118       81 7/subop/compare *edi 0/imm32
 8119       0f 85/jump-if-!= break/disp32
 8120 $find-or-create-typeinfo:create:
 8121       # *out = allocate
 8122       (allocate Heap *Typeinfo-size %edi)
 8123       # var tmp/eax: (addr typeinfo) = lookup(*out)
 8124       (lookup *edi *(edi+4))  # => eax
 8125 #?     (write-buffered Stderr "created typeinfo at ")
 8126 #?     (print-int32-buffered Stderr %eax)
 8127 #?     (write-buffered Stderr " for type-id ")
 8128 #?     (print-int32-buffered Stderr *(ebp+8))
 8129 #?     (write-buffered Stderr Newline)
 8130 #?     (flush Stderr)
 8131       # tmp->id = t
 8132       8b/-> *(ebp+8) 2/r32/edx
 8133       89/<- *eax 2/r32/edx  # Typeinfo-id
 8134       # tmp->fields = new table
 8135       # . fields = new table
 8136       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 8137       # . tmp->fields = fields
 8138       8b/-> *ecx 2/r32/edx
 8139       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 8140       8b/-> *(ecx+4) 2/r32/edx
 8141       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 8142       # tmp->next = Program->types
 8143       8b/-> *_Program-types 1/r32/ecx
 8144       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 8145       8b/-> *_Program-types->payload 1/r32/ecx
 8146       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 8147       # Program->types = out
 8148       8b/-> *edi 1/r32/ecx
 8149       89/<- *_Program-types 1/r32/ecx
 8150       8b/-> *(edi+4) 1/r32/ecx
 8151       89/<- *_Program-types->payload 1/r32/ecx
 8152     }
 8153 $find-or-create-typeinfo:end:
 8154     # . reclaim locals
 8155     81 0/subop/add %esp 8/imm32
 8156     # . restore registers
 8157     5f/pop-to-edi
 8158     5a/pop-to-edx
 8159     59/pop-to-ecx
 8160     58/pop-to-eax
 8161     # . epilogue
 8162     89/<- %esp 5/r32/ebp
 8163     5d/pop-to-ebp
 8164     c3/return
 8165 
 8166 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 8167     # . prologue
 8168     55/push-ebp
 8169     89/<- %ebp 4/r32/esp
 8170     # . save registers
 8171     50/push-eax
 8172     51/push-ecx
 8173     52/push-edx
 8174     57/push-edi
 8175     # ecx = t
 8176     8b/-> *(ebp+8) 1/r32/ecx
 8177     # edi = out
 8178     8b/-> *(ebp+0xc) 7/r32/edi
 8179     # *out = Program->types
 8180     8b/-> *_Program-types 0/r32/eax
 8181     89/<- *edi 0/r32/eax
 8182     8b/-> *_Program-types->payload 0/r32/eax
 8183     89/<- *(edi+4) 0/r32/eax
 8184     {
 8185       # if (*out == 0) break
 8186       81 7/subop/compare *edi 0/imm32
 8187       74/jump-if-= break/disp8
 8188       # var tmp/eax: (addr typeinfo) = lookup(*out)
 8189       (lookup *edi *(edi+4))  # => eax
 8190       # if (tmp->id == t) break
 8191       39/compare *eax 1/r32/ecx  # Typeinfo-id
 8192       74/jump-if-= break/disp8
 8193       # *out = tmp->next
 8194       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 8195       89/<- *edi 2/r32/edx
 8196       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 8197       89/<- *(edi+4) 2/r32/edx
 8198       #
 8199       eb/jump loop/disp8
 8200     }
 8201 $find-typeinfo:end:
 8202     # . restore registers
 8203     5f/pop-to-edi
 8204     5a/pop-to-edx
 8205     59/pop-to-ecx
 8206     58/pop-to-eax
 8207     # . epilogue
 8208     89/<- %esp 5/r32/ebp
 8209     5d/pop-to-ebp
 8210     c3/return
 8211 
 8212 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 8213     # . prologue
 8214     55/push-ebp
 8215     89/<- %ebp 4/r32/esp
 8216     # . save registers
 8217     50/push-eax
 8218     52/push-edx
 8219     57/push-edi
 8220     # var dest/edi: (handle typeinfo-entry)
 8221     68/push 0/imm32
 8222     68/push 0/imm32
 8223     89/<- %edi 4/r32/esp
 8224     # find-or-create-typeinfo-fields(T, f, dest)
 8225     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 8226     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 8227     (lookup *edi *(edi+4))  # => eax
 8228     89/<- %edi 0/r32/eax
 8229     # if dest-addr->output-var doesn't exist, create it
 8230     {
 8231       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 8232       0f 85/jump-if-!= break/disp32
 8233       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 8234       # . var name/eax: (handle array byte) = "field"
 8235       68/push 0/imm32
 8236       68/push 0/imm32
 8237       89/<- %eax 4/r32/esp
 8238       (copy-array Heap "field" %eax)
 8239       # . new var
 8240       8d/copy-address *(edi+0xc) 2/r32/edx
 8241       (new-var Heap  *eax *(eax+4)  %edx)
 8242       # . reclaim name
 8243       81 0/subop/add %esp 8/imm32
 8244       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 8245       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 8246       89/<- %edx 0/r32/eax
 8247       # result->type = new constant type
 8248       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 8249       (allocate Heap *Tree-size %eax)
 8250       (lookup *(edx+8) *(edx+0xc))  # => eax
 8251       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 8252       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 8253       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 8254       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 8255       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 8256       # result->offset isn't filled out yet
 8257       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 8258     }
 8259     # out = dest-addr->output-var
 8260     8b/-> *(ebp+0x10) 2/r32/edx
 8261     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 8262     89/<- *edx 0/r32/eax
 8263     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 8264     89/<- *(edx+4) 0/r32/eax
 8265 $find-or-create-typeinfo-output-var:end:
 8266     # . reclaim locals
 8267     81 0/subop/add %esp 8/imm32
 8268     # . restore registers
 8269     5f/pop-to-edi
 8270     5a/pop-to-edx
 8271     58/pop-to-eax
 8272     # . epilogue
 8273     89/<- %esp 5/r32/ebp
 8274     5d/pop-to-ebp
 8275     c3/return
 8276 
 8277 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 8278     # . prologue
 8279     55/push-ebp
 8280     89/<- %ebp 4/r32/esp
 8281     # . save registers
 8282     50/push-eax
 8283     56/push-esi
 8284     57/push-edi
 8285     # eax = lookup(T->fields)
 8286     8b/-> *(ebp+8) 0/r32/eax
 8287     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 8288     # edi = out
 8289     8b/-> *(ebp+0x10) 7/r32/edi
 8290     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 8291     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 8292     89/<- %esi 0/r32/eax
 8293     # if src doesn't exist, allocate it
 8294     {
 8295       81 7/subop/compare *esi 0/imm32
 8296       75/jump-if-!= break/disp8
 8297       (allocate Heap *Typeinfo-entry-size %esi)
 8298 #?       (write-buffered Stderr "handle at ")
 8299 #?       (print-int32-buffered Stderr %esi)
 8300 #?       (write-buffered Stderr ": ")
 8301 #?       (print-int32-buffered Stderr *esi)
 8302 #?       (write-buffered Stderr " ")
 8303 #?       (print-int32-buffered Stderr *(esi+4))
 8304 #?       (write-buffered Stderr Newline)
 8305 #?       (flush Stderr)
 8306 #?       (lookup *esi *(esi+4))
 8307 #?       (write-buffered Stderr "created typeinfo fields at ")
 8308 #?       (print-int32-buffered Stderr %esi)
 8309 #?       (write-buffered Stderr " for ")
 8310 #?       (print-int32-buffered Stderr *(ebp+8))
 8311 #?       (write-buffered Stderr Newline)
 8312 #?       (flush Stderr)
 8313     }
 8314     # *out = src
 8315     # . *edi = *src
 8316     8b/-> *esi 0/r32/eax
 8317     89/<- *edi 0/r32/eax
 8318     8b/-> *(esi+4) 0/r32/eax
 8319     89/<- *(edi+4) 0/r32/eax
 8320 $find-or-create-typeinfo-fields:end:
 8321     # . restore registers
 8322     5f/pop-to-edi
 8323     5e/pop-to-esi
 8324     58/pop-to-eax
 8325     # . epilogue
 8326     89/<- %esp 5/r32/ebp
 8327     5d/pop-to-ebp
 8328     c3/return
 8329 
 8330 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 8331     # pseudocode:
 8332     #   var line: (stream byte 512)
 8333     #   curr-index = 0
 8334     #   while true
 8335     #     clear-stream(line)
 8336     #     read-line-buffered(in, line)
 8337     #     if line->write == 0
 8338     #       abort
 8339     #     word-slice = next-mu-token(line)
 8340     #     if slice-empty?(word-slice)               # end of line
 8341     #       continue
 8342     #     if slice-equal?(word-slice, "}")
 8343     #       break
 8344     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 8345     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 8346     #     TODO: ensure that r->first is null
 8347     #     r->index = curr-index
 8348     #     curr-index++
 8349     #     r->input-var = v
 8350     #     if r->output-var == 0
 8351     #       r->output-var = new literal
 8352     #     TODO: ensure nothing else in line
 8353     # t->total-size-in-bytes = -2 (not yet initialized)
 8354     # check-input-vars(t, err, ed)
 8355     #
 8356     # . prologue
 8357     55/push-ebp
 8358     89/<- %ebp 4/r32/esp
 8359     # var curr-index: int at *(ebp-4)
 8360     68/push 0/imm32
 8361     # . save registers
 8362     50/push-eax
 8363     51/push-ecx
 8364     52/push-edx
 8365     53/push-ebx
 8366     56/push-esi
 8367     57/push-edi
 8368     # edi = t
 8369     8b/-> *(ebp+0xc) 7/r32/edi
 8370     # var line/ecx: (stream byte 512)
 8371     81 5/subop/subtract %esp 0x200/imm32
 8372     68/push 0x200/imm32/size
 8373     68/push 0/imm32/read
 8374     68/push 0/imm32/write
 8375     89/<- %ecx 4/r32/esp
 8376     # var word-slice/edx: slice
 8377     68/push 0/imm32/end
 8378     68/push 0/imm32/start
 8379     89/<- %edx 4/r32/esp
 8380     # var v/esi: (handle var)
 8381     68/push 0/imm32
 8382     68/push 0/imm32
 8383     89/<- %esi 4/r32/esp
 8384     # var r/ebx: (handle typeinfo-entry)
 8385     68/push 0/imm32
 8386     68/push 0/imm32
 8387     89/<- %ebx 4/r32/esp
 8388     {
 8389 $populate-mu-type:line-loop:
 8390       (clear-stream %ecx)
 8391       (read-line-buffered *(ebp+8) %ecx)
 8392       # if (line->write == 0) abort
 8393       81 7/subop/compare *ecx 0/imm32
 8394       0f 84/jump-if-= $populate-mu-type:abort/disp32
 8395 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 8401       (next-mu-token %ecx %edx)
 8402       # if slice-empty?(word-slice) continue
 8403       (slice-empty? %edx)  # => eax
 8404       3d/compare-eax-and 0/imm32
 8405       0f 85/jump-if-!= loop/disp32
 8406       # if slice-equal?(word-slice, "}") break
 8407       (slice-equal? %edx "}")
 8408       3d/compare-eax-and 0/imm32
 8409       0f 85/jump-if-!= break/disp32
 8410 $populate-mu-type:parse-element:
 8411       # v = parse-var-with-type(word-slice, first-line)
 8412       # must do this first to strip the trailing ':' from word-slice before
 8413       # using it in find-or-create-typeinfo-fields below
 8414       # TODO: clean up that mutation in parse-var-with-type
 8415       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
 8416       # var tmp/ecx
 8417       51/push-ecx
 8418 $populate-mu-type:create-typeinfo-fields:
 8419       # var r/ebx: (handle typeinfo-entry)
 8420       (find-or-create-typeinfo-fields %edi %edx %ebx)
 8421       # r->index = curr-index
 8422       (lookup *ebx *(ebx+4))  # => eax
 8423       8b/-> *(ebp-4) 1/r32/ecx
 8424 #?       (write-buffered Stderr "saving index ")
 8425 #?       (print-int32-buffered Stderr %ecx)
 8426 #?       (write-buffered Stderr " at ")
 8427 #?       (print-int32-buffered Stderr %edi)
 8428 #?       (write-buffered Stderr Newline)
 8429 #?       (flush Stderr)
 8430       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 8431       # ++curr-index
 8432       ff 0/subop/increment *(ebp-4)
 8433 $populate-mu-type:set-input-type:
 8434       # r->input-var = v
 8435       8b/-> *esi 1/r32/ecx
 8436       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 8437       8b/-> *(esi+4) 1/r32/ecx
 8438       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 8439       59/pop-to-ecx
 8440       {
 8441 $populate-mu-type:create-output-type:
 8442         # if (r->output-var == 0) create a new var with some placeholder data
 8443         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 8444         75/jump-if-!= break/disp8
 8445         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 8446         (new-literal Heap %edx %eax)
 8447       }
 8448       e9/jump loop/disp32
 8449     }
 8450 $populate-mu-type:invalidate-total-size-in-bytes:
 8451     # Offsets and total size may not be accurate here since we may not yet
 8452     # have encountered the element types.
 8453     # We'll recompute them separately after parsing the entire program.
 8454     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 8455 $populate-mu-type:validate:
 8456     (check-input-vars *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 8457 $populate-mu-type:end:
 8458     # . reclaim locals
 8459     81 0/subop/add %esp 0x224/imm32
 8460     # . restore registers
 8461     5f/pop-to-edi
 8462     5e/pop-to-esi
 8463     5b/pop-to-ebx
 8464     5a/pop-to-edx
 8465     59/pop-to-ecx
 8466     58/pop-to-eax
 8467     # reclaim curr-index
 8468     81 0/subop/add %esp 4/imm32
 8469     # . epilogue
 8470     89/<- %esp 5/r32/ebp
 8471     5d/pop-to-ebp
 8472     c3/return
 8473 
 8474 $populate-mu-type:abort:
 8475     # error("unexpected top-level command: " word-slice "\n")
 8476     (write-buffered *(ebp+0x10) "incomplete type definition '")
 8477     (type-name *edi)  # Typeinfo-id => eax
 8478     (write-buffered *(ebp+0x10) %eax)
 8479     (write-buffered *(ebp+0x10) "\n")
 8480     (flush *(ebp+0x10))
 8481     (stop *(ebp+0x14) 1)
 8482     # never gets here
 8483 
 8484 check-input-vars:  # t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 8485     # . prologue
 8486     55/push-ebp
 8487     89/<- %ebp 4/r32/esp
 8488     # . save registers
 8489     50/push-eax
 8490     51/push-ecx
 8491     52/push-edx
 8492     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(t->fields)
 8493     8b/-> *(ebp+8) 0/r32/eax
 8494     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 8495     89/<- %ecx 0/r32/eax
 8496     # var table-size/edx: int = table->write
 8497     8b/-> *ecx 2/r32/edx  # stream-write
 8498     # var curr/ecx: (addr table_row) = table->data
 8499     8d/copy-address *(ecx+0xc) 1/r32/ecx
 8500     # var max/edx: (addr table_row) = table->data + table->write
 8501     8d/copy-address *(ecx+edx) 2/r32/edx
 8502     {
 8503 $check-input-vars:loop:
 8504       # if (curr >= max) break
 8505       39/compare %ecx 2/r32/edx
 8506       73/jump-if-addr>= break/disp8
 8507       (lookup *ecx *(ecx+4))  # => eax
 8508       # var t2/eax: (addr typeinfo-entry) = lookup(curr->value)
 8509       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 8510       # if (t2->input-var == null) raise an error
 8511       8b/-> *eax 0/r32/eax  # Typeinfo-entry-input-var
 8512       3d/compare-eax-and 0/imm32/null
 8513       0f 84/jump-if-= $check-input-vars:abort/disp32
 8514       # curr += row-size
 8515       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 8516       #
 8517       eb/jump loop/disp8
 8518     }
 8519 $check-input-vars:end:
 8520     # . restore registers
 8521     5a/pop-to-edx
 8522     59/pop-to-ecx
 8523     58/pop-to-eax
 8524     # . epilogue
 8525     89/<- %esp 5/r32/ebp
 8526     5d/pop-to-ebp
 8527     c3/return
 8528 
 8529 $check-input-vars:abort:
 8530     # error("type " type " has no member called '" curr->name "'\n")
 8531     (write-buffered *(ebp+0xc) "type '")
 8532     # . var tmp/edx: int = t->id << 2
 8533     8b/-> *(ebp+8) 0/r32/eax
 8534     8b/-> *eax 2/r32/edx  # Typeinfo-id
 8535     c1/shift 4/subop/left %edx 2/imm8
 8536     # . var a/edx: (addr array byte) = Type-id->data[tmp]
 8537     b8/copy-to-eax Type-id/imm32
 8538     8b/-> *(eax+edx+0xc) 2/r32/edx
 8539     (write-buffered *(ebp+0xc) %edx)
 8540     (write-buffered *(ebp+0xc) "' has no member called '")
 8541     (lookup *ecx *(ecx+4))  # => eax
 8542     (write-buffered *(ebp+0xc) %eax)
 8543     (write-buffered *(ebp+0xc) "'\n")
 8544     (flush *(ebp+0xc))
 8545     (stop *(ebp+0x10) 1)
 8546     # never gets here
 8547 
 8548 type-name:  # index: int -> result/eax: (addr array byte)
 8549     # . prologue
 8550     55/push-ebp
 8551     89/<- %ebp 4/r32/esp
 8552     #
 8553     (index Type-id *(ebp+8))
 8554 $type-name:end:
 8555     # . epilogue
 8556     89/<- %esp 5/r32/ebp
 8557     5d/pop-to-ebp
 8558     c3/return
 8559 
 8560 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 8561     # . prologue
 8562     55/push-ebp
 8563     89/<- %ebp 4/r32/esp
 8564     # . save registers
 8565     56/push-esi
 8566     # TODO: bounds-check index
 8567     # esi = arr
 8568     8b/-> *(ebp+8) 6/r32/esi
 8569     # eax = index
 8570     8b/-> *(ebp+0xc) 0/r32/eax
 8571     # eax = *(arr + 12 + index)
 8572     8b/-> *(esi+eax+0xc) 0/r32/eax
 8573 $index:end:
 8574     # . restore registers
 8575     5e/pop-to-esi
 8576     # . epilogue
 8577     89/<- %esp 5/r32/ebp
 8578     5d/pop-to-ebp
 8579     c3/return
 8580 
 8581 #######################################################
 8582 # Compute type sizes
 8583 #######################################################
 8584 
 8585 # Compute the sizes of all user-defined types.
 8586 # We'll need the sizes of their elements, which may be other user-defined
 8587 # types, which we will compute as needed.
 8588 
 8589 # Initially, all user-defined types have their sizes set to -2 (invalid)
 8590 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 8591     # . prologue
 8592     55/push-ebp
 8593     89/<- %ebp 4/r32/esp
 8594 $populate-mu-type-sizes:total-sizes:
 8595     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 8596     (lookup *_Program-types *_Program-types->payload)  # => eax
 8597     {
 8598       # if (curr == null) break
 8599       3d/compare-eax-and 0/imm32/null
 8600       74/jump-if-= break/disp8
 8601       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
 8602       # curr = lookup(curr->next)
 8603       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 8604       eb/jump loop/disp8
 8605     }
 8606 $populate-mu-type-sizes:offsets:
 8607     # curr = *Program->types
 8608     (lookup *_Program-types *_Program-types->payload)  # => eax
 8609     {
 8610       # if (curr == null) break
 8611       3d/compare-eax-and 0/imm32/null
 8612       74/jump-if-= break/disp8
 8613       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
 8614       # curr = curr->next
 8615       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 8616       eb/jump loop/disp8
 8617     }
 8618 $populate-mu-type-sizes:end:
 8619     # . epilogue
 8620     89/<- %esp 5/r32/ebp
 8621     5d/pop-to-ebp
 8622     c3/return
 8623 
 8624 # compute sizes of all fields, recursing as necessary
 8625 # sum up all their sizes to arrive at total size
 8626 # fields may be out of order, but that doesn't affect the answer
 8627 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 8628     # . prologue
 8629     55/push-ebp
 8630     89/<- %ebp 4/r32/esp
 8631     # . save registers
 8632     50/push-eax
 8633     51/push-ecx
 8634     52/push-edx
 8635     56/push-esi
 8636     57/push-edi
 8637     # esi = T
 8638     8b/-> *(ebp+8) 6/r32/esi
 8639     # if T is already computed, return
 8640     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 8641     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 8642     # if T is being computed, abort
 8643     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 8644     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
 8645     # tag T (-2 to -1) to avoid infinite recursion
 8646     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 8647     # var total-size/edi: int = 0
 8648     bf/copy-to-edi 0/imm32
 8649     # - for every field, if it's a user-defined type, compute its size
 8650     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 8651     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 8652     89/<- %ecx 0/r32/eax
 8653     # var table-size/edx: int = table->write
 8654     8b/-> *ecx 2/r32/edx  # stream-write
 8655     # var curr/ecx: (addr table_row) = table->data
 8656     8d/copy-address *(ecx+0xc) 1/r32/ecx
 8657     # var max/edx: (addr table_row) = table->data + table->write
 8658     8d/copy-address *(ecx+edx) 2/r32/edx
 8659     {
 8660 $populate-mu-type-sizes-in-type:loop:
 8661       # if (curr >= max) break
 8662       39/compare %ecx 2/r32/edx
 8663       73/jump-if-addr>= break/disp8
 8664       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
 8665       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 8666       # compute size of t->input-var
 8667       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 8668       (compute-size-of-var %eax)  # => eax
 8669       # result += eax
 8670       01/add-to %edi 0/r32/eax
 8671       # curr += row-size
 8672       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 8673       #
 8674       eb/jump loop/disp8
 8675     }
 8676     # - save result
 8677     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
 8678 $populate-mu-type-sizes-in-type:end:
 8679     # . restore registers
 8680     5f/pop-to-edi
 8681     5e/pop-to-esi
 8682     5a/pop-to-edx
 8683     59/pop-to-ecx
 8684     58/pop-to-eax
 8685     # . epilogue
 8686     89/<- %esp 5/r32/ebp
 8687     5d/pop-to-ebp
 8688     c3/return
 8689 
 8690 $populate-mu-type-sizes-in-type:abort:
 8691     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
 8692     (flush *(ebp+0xc))
 8693     (stop *(ebp+0x10) 1)
 8694     # never gets here
 8695 
 8696 # Analogous to size-of, except we need to compute what size-of can just read
 8697 # off the right data structures.
 8698 compute-size-of-var:  # in: (addr var) -> result/eax: int
 8699     # . prologue
 8700     55/push-ebp
 8701     89/<- %ebp 4/r32/esp
 8702     # . push registers
 8703     51/push-ecx
 8704     # var t/ecx: (addr tree type-id) = lookup(v->type)
 8705     8b/-> *(ebp+8) 1/r32/ecx
 8706     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8707     89/<- %ecx 0/r32/eax
 8708     # if (t->is-atom == false) t = lookup(t->left)
 8709     {
 8710       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8711       75/jump-if-!= break/disp8
 8712       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8713       89/<- %ecx 0/r32/eax
 8714     }
 8715     # TODO: ensure t is an atom
 8716     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
 8717 $compute-size-of-var:end:
 8718     # . restore registers
 8719     59/pop-to-ecx
 8720     # . epilogue
 8721     89/<- %esp 5/r32/ebp
 8722     5d/pop-to-ebp
 8723     c3/return
 8724 
 8725 compute-size-of-type-id:  # t: type-id -> result/eax: int
 8726     # . prologue
 8727     55/push-ebp
 8728     89/<- %ebp 4/r32/esp
 8729     # . save registers
 8730     51/push-ecx
 8731     # var out/ecx: (handle typeinfo)
 8732     68/push 0/imm32
 8733     68/push 0/imm32
 8734     89/<- %ecx 4/r32/esp
 8735     # eax = t
 8736     8b/-> *(ebp+8) 0/r32/eax
 8737     # if t is a literal, return 0
 8738     3d/compare-eax-and 0/imm32/literal
 8739     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
 8740     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
 8741     3d/compare-eax-and 8/imm32/byte
 8742     {
 8743       75/jump-if-!= break/disp8
 8744       b8/copy-to-eax 4/imm32
 8745       eb/jump $compute-size-of-type-id:end/disp8
 8746     }
 8747     # if t is a handle, return 8
 8748     3d/compare-eax-and 4/imm32/handle
 8749     {
 8750       75/jump-if-!= break/disp8
 8751       b8/copy-to-eax 8/imm32
 8752       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
 8753     }
 8754     # if t is a user-defined type, compute its size
 8755     # TODO: support non-atom type
 8756     (find-typeinfo %eax %ecx)
 8757     {
 8758       81 7/subop/compare *ecx 0/imm32
 8759       74/jump-if-= break/disp8
 8760 $compute-size-of-type-id:user-defined:
 8761       (populate-mu-type-sizes %eax)
 8762       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 8763       eb/jump $compute-size-of-type-id:end/disp8
 8764     }
 8765     # otherwise return the word size
 8766     b8/copy-to-eax 4/imm32
 8767 $compute-size-of-type-id:end:
 8768     # . reclaim locals
 8769     81 0/subop/add %esp 8/imm32
 8770     # . restore registers
 8771     59/pop-to-ecx
 8772     # . epilogue
 8773     89/<- %esp 5/r32/ebp
 8774     5d/pop-to-ebp
 8775     c3/return
 8776 
 8777 # at this point we have total sizes for all user-defined types
 8778 # compute offsets for each element
 8779 # complication: fields may be out of order
 8780 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 8781     # . prologue
 8782     55/push-ebp
 8783     89/<- %ebp 4/r32/esp
 8784     # . save registers
 8785     50/push-eax
 8786     51/push-ecx
 8787     52/push-edx
 8788     53/push-ebx
 8789     56/push-esi
 8790     57/push-edi
 8791 #?     (dump-typeinfos "aaa\n")
 8792     # var curr-offset/edi: int = 0
 8793     bf/copy-to-edi 0/imm32
 8794     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
 8795     8b/-> *(ebp+8) 1/r32/ecx
 8796     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
 8797     89/<- %ecx 0/r32/eax
 8798     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
 8799     8b/-> *ecx 2/r32/edx  # stream-write
 8800     c1 5/subop/shift-right-logical  %edx 4/imm8
 8801     # var i/ebx: int = 0
 8802     bb/copy-to-ebx 0/imm32
 8803     {
 8804 $populate-mu-type-offsets:loop:
 8805       39/compare %ebx 2/r32/edx
 8806       7d/jump-if->= break/disp8
 8807 #?       (write-buffered Stderr "looking up index ")
 8808 #?       (print-int32-buffered Stderr %ebx)
 8809 #?       (write-buffered Stderr " in ")
 8810 #?       (print-int32-buffered Stderr *(ebp+8))
 8811 #?       (write-buffered Stderr Newline)
 8812 #?       (flush Stderr)
 8813       # var v/esi: (addr typeinfo-entry)
 8814       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
 8815       89/<- %esi 0/r32/eax
 8816       # v->output-var->offset = curr-offset
 8817       # . eax: (addr var)
 8818       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
 8819       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
 8820       # curr-offset += size-of(v->input-var)
 8821       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 8822       (size-of %eax)  # => eax
 8823       01/add-to %edi 0/r32/eax
 8824       # ++i
 8825       43/increment-ebx
 8826       eb/jump loop/disp8
 8827     }
 8828 $populate-mu-type-offsets:end:
 8829     # . restore registers
 8830     5f/pop-to-edi
 8831     5e/pop-to-esi
 8832     5b/pop-to-ebx
 8833     5a/pop-to-edx
 8834     59/pop-to-ecx
 8835     58/pop-to-eax
 8836     # . epilogue
 8837     89/<- %esp 5/r32/ebp
 8838     5d/pop-to-ebp
 8839     c3/return
 8840 
 8841 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)
 8842     # . prologue
 8843     55/push-ebp
 8844     89/<- %ebp 4/r32/esp
 8845     # . save registers
 8846     51/push-ecx
 8847     52/push-edx
 8848     53/push-ebx
 8849     56/push-esi
 8850     57/push-edi
 8851     # esi = table
 8852     8b/-> *(ebp+8) 6/r32/esi
 8853     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
 8854     8d/copy-address *(esi+0xc) 1/r32/ecx
 8855     # var max/edx: (addr byte) = &table->data[table->write]
 8856     8b/-> *esi 2/r32/edx
 8857     8d/copy-address *(ecx+edx) 2/r32/edx
 8858     {
 8859 $locate-typeinfo-entry-with-index:loop:
 8860       39/compare %ecx 2/r32/edx
 8861       73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8
 8862       # var v/eax: (addr typeinfo-entry)
 8863       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 8864       # if (v->index == idx) return v
 8865       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
 8866 #?       (write-buffered Stderr "comparing ")
 8867 #?       (print-int32-buffered Stderr %ebx)
 8868 #?       (write-buffered Stderr " and ")
 8869 #?       (print-int32-buffered Stderr *(ebp+0xc))
 8870 #?       (write-buffered Stderr Newline)
 8871 #?       (flush Stderr)
 8872       39/compare *(ebp+0xc) 3/r32/ebx
 8873       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
 8874       # curr += Typeinfo-entry-size
 8875       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
 8876       #
 8877       eb/jump loop/disp8
 8878     }
 8879     # return 0
 8880     b8/copy-to-eax 0/imm32
 8881 $locate-typeinfo-entry-with-index:end:
 8882 #?     (write-buffered Stderr "returning ")
 8883 #?     (print-int32-buffered Stderr %eax)
 8884 #?     (write-buffered Stderr Newline)
 8885 #?     (flush Stderr)
 8886     # . restore registers
 8887     5f/pop-to-edi
 8888     5e/pop-to-esi
 8889     5b/pop-to-ebx
 8890     5a/pop-to-edx
 8891     59/pop-to-ecx
 8892     # . epilogue
 8893     89/<- %esp 5/r32/ebp
 8894     5d/pop-to-ebp
 8895     c3/return
 8896 
 8897 $locate-typeinfo-entry-with-index:abort:
 8898     (write-buffered *(ebp+0x10) "overflowing typeinfo-entry->index ")
 8899     (print-int32-buffered *(ebp+0x10) %ecx)
 8900     (write-buffered *(ebp+0x10) "\n")
 8901     (flush *(ebp+0x10))
 8902     (stop *(ebp+0x14) 1)
 8903     # never gets here
 8904 
 8905 dump-typeinfos:  # hdr: (addr array byte)
 8906     # . prologue
 8907     55/push-ebp
 8908     89/<- %ebp 4/r32/esp
 8909     # . save registers
 8910     50/push-eax
 8911     #
 8912     (write-buffered Stderr *(ebp+8))
 8913     (flush Stderr)
 8914     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 8915     (lookup *_Program-types *_Program-types->payload)  # => eax
 8916     {
 8917       # if (curr == null) break
 8918       3d/compare-eax-and 0/imm32
 8919       74/jump-if-= break/disp8
 8920       (write-buffered Stderr "---\n")
 8921       (flush Stderr)
 8922       (dump-typeinfo %eax)
 8923       # curr = lookup(curr->next)
 8924       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 8925       eb/jump loop/disp8
 8926     }
 8927 $dump-typeinfos:end:
 8928     # . restore registers
 8929     58/pop-to-eax
 8930     # . epilogue
 8931     89/<- %esp 5/r32/ebp
 8932     5d/pop-to-ebp
 8933     c3/return
 8934 
 8935 dump-typeinfo:  # in: (addr typeinfo)
 8936     # . prologue
 8937     55/push-ebp
 8938     89/<- %ebp 4/r32/esp
 8939     # . save registers
 8940     50/push-eax
 8941     51/push-ecx
 8942     52/push-edx
 8943     53/push-ebx
 8944     56/push-esi
 8945     57/push-edi
 8946     # esi = in
 8947     8b/-> *(ebp+8) 6/r32/esi
 8948     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 8949     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 8950     89/<- %ecx 0/r32/eax
 8951     (write-buffered Stderr "id:")
 8952     (print-int32-buffered Stderr *esi)
 8953     (write-buffered Stderr "\n")
 8954     (write-buffered Stderr "fields @ ")
 8955     (print-int32-buffered Stderr %ecx)
 8956     (write-buffered Stderr Newline)
 8957     (flush Stderr)
 8958     (write-buffered Stderr "  write: ")
 8959     (print-int32-buffered Stderr *ecx)
 8960     (write-buffered Stderr Newline)
 8961     (flush Stderr)
 8962     (write-buffered Stderr "  read: ")
 8963     (print-int32-buffered Stderr *(ecx+4))
 8964     (write-buffered Stderr Newline)
 8965     (flush Stderr)
 8966     (write-buffered Stderr "  size: ")
 8967     (print-int32-buffered Stderr *(ecx+8))
 8968     (write-buffered Stderr Newline)
 8969     (flush Stderr)
 8970     # var table-size/edx: int = table->write
 8971     8b/-> *ecx 2/r32/edx  # stream-write
 8972     # var curr/ecx: (addr table_row) = table->data
 8973     8d/copy-address *(ecx+0xc) 1/r32/ecx
 8974     # var max/edx: (addr table_row) = table->data + table->write
 8975     8d/copy-address *(ecx+edx) 2/r32/edx
 8976     {
 8977 $dump-typeinfo:loop:
 8978       # if (curr >= max) break
 8979       39/compare %ecx 2/r32/edx
 8980       0f 83/jump-if-addr>= break/disp32
 8981       (write-buffered Stderr "  row:\n")
 8982       (write-buffered Stderr "    key: ")
 8983       (print-int32-buffered Stderr *ecx)
 8984       (write-buffered Stderr ",")
 8985       (print-int32-buffered Stderr *(ecx+4))
 8986       (write-buffered Stderr " = '")
 8987       (lookup *ecx *(ecx+4))
 8988       (write-buffered Stderr %eax)
 8989       (write-buffered Stderr "' @ ")
 8990       (print-int32-buffered Stderr %eax)
 8991       (write-buffered Stderr Newline)
 8992       (flush Stderr)
 8993       (write-buffered Stderr "    value: ")
 8994       (print-int32-buffered Stderr *(ecx+8))
 8995       (write-buffered Stderr ",")
 8996       (print-int32-buffered Stderr *(ecx+0xc))
 8997       (write-buffered Stderr " = typeinfo-entry@")
 8998       (lookup *(ecx+8) *(ecx+0xc))
 8999       (print-int32-buffered Stderr %eax)
 9000       (write-buffered Stderr Newline)
 9001       (flush Stderr)
 9002       (write-buffered Stderr "        input var@")
 9003       (print-int32-buffered Stderr *eax)
 9004       (write-buffered Stderr ",")
 9005       (print-int32-buffered Stderr *(eax+4))
 9006       (write-buffered Stderr "->")
 9007       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var
 9008       (print-int32-buffered Stderr %eax)
 9009       {
 9010         3d/compare-eax-and 0/imm32
 9011         74/jump-if-= break/disp8
 9012         (write-buffered Stderr " ")
 9013         # TODO
 9014       }
 9015       (write-buffered Stderr Newline)
 9016       (flush Stderr)
 9017       (lookup *(ecx+8) *(ecx+0xc))
 9018       (write-buffered Stderr "        index: ")
 9019       (print-int32-buffered Stderr *(eax+8))
 9020       (write-buffered Stderr Newline)
 9021       (flush Stderr)
 9022       (write-buffered Stderr "        output var@")
 9023       (print-int32-buffered Stderr *(eax+0xc))
 9024       (write-buffered Stderr ",")
 9025       (print-int32-buffered Stderr *(eax+0x10))
 9026       (write-buffered Stderr "->")
 9027       (lookup *(eax+0xc) *(eax+0x10))  # Typeinfo-entry-output-var
 9028       (print-int32-buffered Stderr %eax)
 9029       (write-buffered Stderr Newline)
 9030       (flush Stderr)
 9031       {
 9032         3d/compare-eax-and 0/imm32
 9033         0f 84/jump-if-= break/disp32
 9034         (write-buffered Stderr "          name: ")
 9035         89/<- %ebx 0/r32/eax
 9036         (print-int32-buffered Stderr *ebx)  # Var-name
 9037         (write-buffered Stderr ",")
 9038         (print-int32-buffered Stderr *(ebx+4))  # Var-name
 9039         (write-buffered Stderr "->")
 9040         (lookup *ebx *(ebx+4))  # Var-name
 9041         (print-int32-buffered Stderr %eax)
 9042         {
 9043           3d/compare-eax-and 0/imm32
 9044           74/jump-if-= break/disp8
 9045           (write-buffered Stderr Space)
 9046           (write-buffered Stderr %eax)
 9047         }
 9048         (write-buffered Stderr Newline)
 9049         (flush Stderr)
 9050         (write-buffered Stderr "          block depth: ")
 9051         (print-int32-buffered Stderr *(ebx+0x10))  # Var-block-depth
 9052         (write-buffered Stderr Newline)
 9053         (flush Stderr)
 9054         (write-buffered Stderr "          stack offset: ")
 9055         (print-int32-buffered Stderr *(ebx+0x14))  # Var-offset
 9056         (write-buffered Stderr Newline)
 9057         (flush Stderr)
 9058         (write-buffered Stderr "          reg: ")
 9059         (print-int32-buffered Stderr *(ebx+0x18))  # Var-register
 9060         (write-buffered Stderr ",")
 9061         (print-int32-buffered Stderr *(ebx+0x1c))  # Var-register
 9062         (write-buffered Stderr "->")
 9063         (flush Stderr)
 9064         (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
 9065         (print-int32-buffered Stderr %eax)
 9066         {
 9067           3d/compare-eax-and 0/imm32
 9068           74/jump-if-= break/disp8
 9069           (write-buffered Stderr Space)
 9070           (write-buffered Stderr %eax)
 9071         }
 9072         (write-buffered Stderr Newline)
 9073         (flush Stderr)
 9074       }
 9075       (flush Stderr)
 9076       # curr += row-size
 9077       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 9078       #
 9079       e9/jump loop/disp32
 9080     }
 9081 $dump-typeinfo:end:
 9082     # . restore registers
 9083     5f/pop-to-edi
 9084     5e/pop-to-esi
 9085     5b/pop-to-ebx
 9086     5a/pop-to-edx
 9087     59/pop-to-ecx
 9088     58/pop-to-eax
 9089     # . epilogue
 9090     89/<- %esp 5/r32/ebp
 9091     5d/pop-to-ebp
 9092     c3/return
 9093 
 9094 #######################################################
 9095 # Type-checking
 9096 #######################################################
 9097 
 9098 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 9099     # . prologue
 9100     55/push-ebp
 9101     89/<- %ebp 4/r32/esp
 9102     # . save registers
 9103     50/push-eax
 9104     # var curr/eax: (addr function) = *Program->functions
 9105     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 9106     {
 9107 $check-mu-types:loop:
 9108       # if (curr == null) break
 9109       3d/compare-eax-and 0/imm32
 9110       0f 84/jump-if-= break/disp32
 9111       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
 9112       # curr = lookup(curr->next)
 9113       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 9114       e9/jump loop/disp32
 9115     }
 9116 $check-mu-types:end:
 9117     # . restore registers
 9118     58/pop-to-eax
 9119     # . epilogue
 9120     89/<- %esp 5/r32/ebp
 9121     5d/pop-to-ebp
 9122     c3/return
 9123 
 9124 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9125     # . prologue
 9126     55/push-ebp
 9127     89/<- %ebp 4/r32/esp
 9128     # . save registers
 9129     50/push-eax
 9130     # eax = f
 9131     8b/-> *(ebp+8) 0/r32/eax
 9132     # TODO: anything to check in header?
 9133     # var body/eax: (addr block) = lookup(f->body)
 9134     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
 9135     (check-mu-block %eax *(ebp+0xc) *(ebp+0x10))
 9136 $check-mu-function:end:
 9137     # . restore registers
 9138     58/pop-to-eax
 9139     # . epilogue
 9140     89/<- %esp 5/r32/ebp
 9141     5d/pop-to-ebp
 9142     c3/return
 9143 
 9144 check-mu-block:  # block: (addr block), err: (addr buffered-file), ed: (addr exit-descriptor)
 9145     # . prologue
 9146     55/push-ebp
 9147     89/<- %ebp 4/r32/esp
 9148     # . save registers
 9149     50/push-eax
 9150     # eax = block
 9151     8b/-> *(ebp+8) 0/r32/eax
 9152     # var stmts/eax: (addr list stmt) = lookup(block->statements)
 9153     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
 9154     #
 9155     {
 9156 $check-mu-block:check-empty:
 9157       3d/compare-eax-and 0/imm32
 9158       0f 84/jump-if-= break/disp32
 9159       # emit block->statements
 9160       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10))
 9161     }
 9162 $check-mu-block:end:
 9163     # . restore registers
 9164     58/pop-to-eax
 9165     # . epilogue
 9166     89/<- %esp 5/r32/ebp
 9167     5d/pop-to-ebp
 9168     c3/return
 9169 
 9170 check-mu-stmt-list:  # stmts: (addr list stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9171     # . prologue
 9172     55/push-ebp
 9173     89/<- %ebp 4/r32/esp
 9174     # . save registers
 9175     50/push-eax
 9176     56/push-esi
 9177     # esi = stmts
 9178     8b/-> *(ebp+8) 6/r32/esi
 9179     {
 9180 $check-mu-stmt-list:loop:
 9181       81 7/subop/compare %esi 0/imm32
 9182       0f 84/jump-if-= break/disp32
 9183       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
 9184       (lookup *esi *(esi+4))  # List-value List-value => eax
 9185       {
 9186 $check-mu-stmt-list:check-for-block:
 9187         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
 9188         75/jump-if-!= break/disp8
 9189 $check-mu-stmt-list:block:
 9190         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10))
 9191         eb/jump $check-mu-stmt-list:continue/disp8
 9192       }
 9193       {
 9194 $check-mu-stmt-list:check-for-stmt1:
 9195         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
 9196         0f 85/jump-if-!= break/disp32
 9197 $check-mu-stmt-list:stmt1:
 9198         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10))
 9199         eb/jump $check-mu-stmt-list:continue/disp8
 9200       }
 9201       {
 9202 $check-mu-stmt-list:check-for-reg-var-def:
 9203         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
 9204         0f 85/jump-if-!= break/disp32
 9205 $check-mu-stmt-list:reg-var-def:
 9206         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10))
 9207         eb/jump $check-mu-stmt-list:continue/disp8
 9208       }
 9209 $check-mu-stmt-list:continue:
 9210       # TODO: raise an error on unrecognized Stmt-tag
 9211       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
 9212       89/<- %esi 0/r32/eax
 9213       e9/jump loop/disp32
 9214     }
 9215 $check-mu-stmt-list:end:
 9216     # . restore registers
 9217     5e/pop-to-esi
 9218     58/pop-to-eax
 9219     # . epilogue
 9220     89/<- %esp 5/r32/ebp
 9221     5d/pop-to-ebp
 9222     c3/return
 9223 
 9224 check-mu-stmt:  # stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9225     # . prologue
 9226     55/push-ebp
 9227     89/<- %ebp 4/r32/esp
 9228     # . save registers
 9229     50/push-eax
 9230     51/push-ecx
 9231     52/push-edx
 9232     53/push-ebx
 9233     56/push-esi
 9234     57/push-edi
 9235     # esi = stmt
 9236     8b/-> *(ebp+8) 6/r32/esi
 9237     # var f/edi: (addr function) = lookup(*Program->functions)
 9238     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 9239     (find-matching-function %eax *(ebp+8))  # => eax
 9240     89/<- %edi 0/r32/eax
 9241     {
 9242 $check-mu-stmt:check-for-call:
 9243       81 7/subop/compare %edi 0/imm32
 9244       0f 84/jump-if-= break/disp32
 9245 $check-mu-stmt:is-call:
 9246       # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
 9247       (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9248       89/<- %ecx 0/r32/eax
 9249       # var expected/edx: (addr list var) = lookup(f->inouts)
 9250       (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
 9251       89/<- %edx 0/r32/eax
 9252       {
 9253 $check-mu-stmt:check-for-inouts:
 9254         # if (inouts == 0) break
 9255         81 7/subop/compare %ecx 0/imm32
 9256         0f 84/jump-if-= break/disp32
 9257         # if (expected == 0) error
 9258         81 7/subop/compare %edx 0/imm32
 9259         0f 84/jump-if-= break/disp32
 9260 $check-mu-stmt:check-inout-type:
 9261         # var v/eax: (addr v) = lookup(inouts->value)
 9262         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9263         # var t/ebx: (addr tree type-id) = lookup(v->type)
 9264         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9265         89/<- %ebx 0/r32/eax
 9266         # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
 9267         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9268         {
 9269           74/jump-if-= break/disp8
 9270           (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
 9271           89/<- %ebx 0/r32/eax
 9272           # if t->right is null, t = t->left
 9273           81 7/subop/compare *(ebx+0xc) 0/imm32  # Tree-right
 9274           75/jump-if-!= break/disp8
 9275           (lookup *(ebx+4) *(ebx+8))  # Tree-left Tree-left => eax
 9276           89/<- %ebx 0/r32/eax
 9277         }
 9278         # var v2/eax: (addr v) = lookup(expected->value)
 9279         (lookup *edx *(edx+4))  # List-value List-value => eax
 9280         # var t2/eax: (addr tree type-id) = lookup(v2->type)
 9281         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9282         # if (t != t2) error
 9283         (type-match? %eax %ebx)  # => eax
 9284         3d/compare-eax-and 0/imm32/false
 9285         {
 9286           0f 85/jump-if-!= break/disp32
 9287           (write-buffered *(ebp+0xc) "call ")
 9288           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9289           (write-buffered *(ebp+0xc) %eax)
 9290           (write-buffered *(ebp+0xc) ": type for inout '")
 9291           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9292           (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9293           (write-buffered *(ebp+0xc) %eax)
 9294           (write-buffered *(ebp+0xc) "' is not right\n")
 9295           (flush *(ebp+0xc))
 9296           (stop *(ebp+0x10) 1)
 9297         }
 9298 $check-mu-stmt:continue-to-next-inout:
 9299         # inouts = lookup(inouts->next)
 9300         (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9301         89/<- %ecx 0/r32/eax
 9302         # expected = lookup(expected->next)
 9303         (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 9304         89/<- %edx 0/r32/eax
 9305         #
 9306         e9/jump loop/disp32
 9307       }
 9308 $check-mu-stmt:check-inout-count:
 9309       # if (inouts == expected) proceed
 9310       39/compare %ecx 2/r32/edx
 9311       {
 9312         0f 84/jump-if-= break/disp32
 9313         # exactly one of the two is null
 9314         # if (inouts == 0) error("too many args")
 9315         {
 9316           81 7/subop/compare %ecx 0/imm32
 9317           74/jump-if-= break/disp8
 9318           (write-buffered *(ebp+0xc) "call ")
 9319           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9320           (write-buffered *(ebp+0xc) %eax)
 9321           (write-buffered *(ebp+0xc) ": too many inouts\n")
 9322           (flush *(ebp+0xc))
 9323           (stop *(ebp+0x10) 1)
 9324         }
 9325         # if (expected == 0) error("too few args")
 9326         {
 9327           81 7/subop/compare %edx 0/imm32
 9328           74/jump-if-= break/disp8
 9329           (write-buffered *(ebp+0xc) "call ")
 9330           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9331           (write-buffered *(ebp+0xc) %eax)
 9332           (write-buffered *(ebp+0xc) ": too few inouts\n")
 9333           (flush *(ebp+0xc))
 9334           (stop *(ebp+0x10) 1)
 9335         }
 9336       }
 9337 $check-mu-stmt:check-outputs:
 9338       # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
 9339       (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9340       89/<- %ecx 0/r32/eax
 9341       # var expected/edx: (addr list var) = lookup(f->outputs)
 9342       (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
 9343       89/<- %edx 0/r32/eax
 9344       {
 9345 $check-mu-stmt:check-for-outputs:
 9346         # if (outputs == 0) break
 9347         81 7/subop/compare %ecx 0/imm32
 9348         0f 84/jump-if-= break/disp32
 9349         # if (expected == 0) error
 9350         81 7/subop/compare %edx 0/imm32
 9351         0f 84/jump-if-= break/disp32
 9352 $check-mu-stmt:check-output-type:
 9353         # var v/eax: (addr v) = lookup(outputs->value)
 9354         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9355         # var t/ebx: (addr tree type-id) = lookup(v->type)
 9356         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9357         89/<- %ebx 0/r32/eax
 9358         # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
 9359         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9360         {
 9361           74/jump-if-= break/disp8
 9362           (lookup *(ebx+0xc) *(ebx+0x10))  # Tree-right Tree-right => eax
 9363           89/<- %ebx 0/r32/eax
 9364         }
 9365         # var v2/eax: (addr v) = lookup(expected->value)
 9366         (lookup *edx *(edx+4))  # List-value List-value => eax
 9367         # var t2/eax: (addr tree type-id) = lookup(v2->type)
 9368         (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9369         # if (t != t2) error
 9370         (type-equal? %eax %ebx)  # => eax
 9371         3d/compare-eax-and 0/imm32/false
 9372         {
 9373           0f 85/jump-if-!= break/disp32
 9374           (write-buffered *(ebp+0xc) "call ")
 9375           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9376           (write-buffered *(ebp+0xc) %eax)
 9377           (write-buffered *(ebp+0xc) ": type for output '")
 9378           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9379           (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9380           (write-buffered *(ebp+0xc) %eax)
 9381           (write-buffered *(ebp+0xc) "' is not right\n")
 9382           (flush *(ebp+0xc))
 9383           (stop *(ebp+0x10) 1)
 9384         }
 9385 $check-mu-stmt:check-output-register:
 9386         # var v/eax: (addr v) = lookup(outputs->value)
 9387         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9388         # var r/ebx: (addr array byte) = lookup(v->register)
 9389         (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
 9390         89/<- %ebx 0/r32/eax
 9391         # var v2/eax: (addr v) = lookup(expected->value)
 9392         (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
 9393         # var r2/eax: (addr array byte) = lookup(v2->register)
 9394         (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
 9395         # if (r != r2) error
 9396         (string-equal? %eax %ebx)  # => eax
 9397         3d/compare-eax-and 0/imm32/false
 9398         {
 9399           0f 85/jump-if-!= break/disp32
 9400           (write-buffered *(ebp+0xc) "call ")
 9401           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9402           (write-buffered *(ebp+0xc) %eax)
 9403           (write-buffered *(ebp+0xc) ": register for output '")
 9404           (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9405           (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9406           (write-buffered *(ebp+0xc) %eax)
 9407           (write-buffered *(ebp+0xc) "' is not right\n")
 9408           (flush *(ebp+0xc))
 9409           (stop *(ebp+0x10) 1)
 9410         }
 9411 $check-mu-stmt:continue-to-next-output:
 9412         # outputs = lookup(outputs->next)
 9413         (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9414         89/<- %ecx 0/r32/eax
 9415         # expected = lookup(expected->next)
 9416         (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 9417         89/<- %edx 0/r32/eax
 9418         #
 9419         e9/jump loop/disp32
 9420       }
 9421 $check-mu-stmt:check-output-count:
 9422       # if (outputs == expected) proceed
 9423       39/compare %ecx 2/r32/edx
 9424       {
 9425         0f 84/jump-if-= break/disp32
 9426         # exactly one of the two is null
 9427         # if (outputs == 0) error("too many outputs")
 9428         {
 9429           81 7/subop/compare %ecx 0/imm32
 9430           74/jump-if-= break/disp8
 9431           (write-buffered *(ebp+0xc) "call ")
 9432           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9433           (write-buffered *(ebp+0xc) %eax)
 9434           (write-buffered *(ebp+0xc) ": too many outputs\n")
 9435           (flush *(ebp+0xc))
 9436           (stop *(ebp+0x10) 1)
 9437         }
 9438         # if (expected == 0) error("too few outputs")
 9439         {
 9440           81 7/subop/compare %edx 0/imm32
 9441           74/jump-if-= break/disp8
 9442           (write-buffered *(ebp+0xc) "call ")
 9443           (lookup *edi *(edi+4))  # Function-name Function-name => eax
 9444           (write-buffered *(ebp+0xc) %eax)
 9445           (write-buffered *(ebp+0xc) ": too few outputs\n")
 9446           (flush *(ebp+0xc))
 9447           (stop *(ebp+0x10) 1)
 9448         }
 9449       }
 9450     }
 9451 $check-mu-stmt:end:
 9452     # . restore registers
 9453     5f/pop-to-edi
 9454     5e/pop-to-esi
 9455     5b/pop-to-ebx
 9456     5a/pop-to-edx
 9457     59/pop-to-ecx
 9458     58/pop-to-eax
 9459     # . epilogue
 9460     89/<- %esp 5/r32/ebp
 9461     5d/pop-to-ebp
 9462     c3/return
 9463 
 9464 # like type-equal? but takes literals into account
 9465 type-match?:  # def: (addr tree type-id), call: (addr tree type-id) -> result/eax: boolean
 9466     # . prologue
 9467     55/push-ebp
 9468     89/<- %ebp 4/r32/esp
 9469     # if (call == literal) return true  # TODO: more precise
 9470     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
 9471     3d/compare-eax-and 0/imm32/false
 9472     b8/copy-to-eax 1/imm32/true
 9473     75/jump-if-!= $type-match?:end/disp8
 9474 $type-match?:baseline:
 9475     # otherwise fall back
 9476     (type-equal? *(ebp+8) *(ebp+0xc))  # => eax
 9477 $type-match?:end:
 9478     # . epilogue
 9479     89/<- %esp 5/r32/ebp
 9480     5d/pop-to-ebp
 9481     c3/return
 9482 
 9483 size-of:  # v: (addr var) -> result/eax: int
 9484     # . prologue
 9485     55/push-ebp
 9486     89/<- %ebp 4/r32/esp
 9487     # . save registers
 9488     51/push-ecx
 9489     # var t/ecx: (addr tree type-id) = lookup(v->type)
 9490     8b/-> *(ebp+8) 1/r32/ecx
 9491 #?     (write-buffered Stderr "size-of ")
 9492 #?     (print-int32-buffered Stderr %ecx)
 9493 #?     (write-buffered Stderr Newline)
 9494 #?     (write-buffered Stderr "type allocid: ")
 9495 #?     (print-int32-buffered Stderr *(ecx+8))
 9496 #?     (write-buffered Stderr Newline)
 9497 #?     (flush Stderr)
 9498     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9499     89/<- %ecx 0/r32/eax
 9500     # if is-mu-array?(t) return size-of-array(t)
 9501     {
 9502       (is-mu-array? %ecx)  # => eax
 9503       3d/compare-eax-and 0/imm32/false
 9504       74/jump-if-= break/disp8
 9505       (size-of-array %ecx)  # => eax
 9506       eb/jump $size-of:end/disp8
 9507     }
 9508     # if (!t->is-atom?) t = lookup(t->left)
 9509     {
 9510       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 9511       75/jump-if-!= break/disp8
 9512       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9513       89/<- %ecx 0/r32/eax
 9514     }
 9515     # TODO: assert t->is-atom?
 9516     (size-of-type-id *(ecx+4))  # Tree-value => eax
 9517 $size-of:end:
 9518     # . restore registers
 9519     59/pop-to-ecx
 9520     # . epilogue
 9521     89/<- %esp 5/r32/ebp
 9522     5d/pop-to-ebp
 9523     c3/return
 9524 
 9525 size-of-deref:  # v: (addr var) -> result/eax: int
 9526     # . prologue
 9527     55/push-ebp
 9528     89/<- %ebp 4/r32/esp
 9529     # . save registers
 9530     51/push-ecx
 9531     # var t/ecx: (addr tree type-id) = lookup(v->type)
 9532     8b/-> *(ebp+8) 1/r32/ecx
 9533     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9534     89/<- %ecx 0/r32/eax
 9535     # TODO: assert(t is an addr)
 9536     # t = lookup(t->right)
 9537     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 9538     89/<- %ecx 0/r32/eax
 9539     # if is-mu-array?(t) return size-of-array(t)
 9540     {
 9541       (is-mu-array? %ecx)  # => eax
 9542       3d/compare-eax-and 0/imm32/false
 9543       74/jump-if-= break/disp8
 9544       (size-of-array %ecx)  # => eax
 9545       eb/jump $size-of:end/disp8
 9546     }
 9547     # if (!t->is-atom?) t = lookup(t->left)
 9548     {
 9549       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 9550       75/jump-if-!= break/disp8
 9551       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9552       89/<- %ecx 0/r32/eax
 9553     }
 9554     # TODO: assert t->is-atom?
 9555     (size-of-type-id *(ecx+4))  # Tree-value => eax
 9556 $size-of-deref:end:
 9557     # . restore registers
 9558     59/pop-to-ecx
 9559     # . epilogue
 9560     89/<- %esp 5/r32/ebp
 9561     5d/pop-to-ebp
 9562     c3/return
 9563 
 9564 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
 9565     # . prologue
 9566     55/push-ebp
 9567     89/<- %ebp 4/r32/esp
 9568     # . save registers
 9569     51/push-ecx
 9570     # ecx = t
 9571     8b/-> *(ebp+8) 1/r32/ecx
 9572     # if t->is-atom?, return false
 9573     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 9574     75/jump-if-!= $is-mu-array?:return-false/disp8
 9575     # if !t->left->is-atom?, return false
 9576     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9577     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 9578     74/jump-if-= $is-mu-array?:return-false/disp8
 9579     # return t->left->value == array
 9580     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
 9581     0f 94/set-if-= %al
 9582     81 4/subop/and %eax 0xff/imm32
 9583     eb/jump $is-mu-array?:end/disp8
 9584 $is-mu-array?:return-false:
 9585     b8/copy-to-eax 0/imm32/false
 9586 $is-mu-array?:end:
 9587     # . restore registers
 9588     59/pop-to-ecx
 9589     # . epilogue
 9590     89/<- %esp 5/r32/ebp
 9591     5d/pop-to-ebp
 9592     c3/return
 9593 
 9594 size-of-array:  # a: (addr tree type-id) -> result/eax: int
 9595     # . prologue
 9596     55/push-ebp
 9597     89/<- %ebp 4/r32/esp
 9598     # . save registers
 9599     51/push-ecx
 9600     52/push-edx
 9601     #
 9602     8b/-> *(ebp+8) 1/r32/ecx
 9603     # TODO: assert that a->left is 'array'
 9604     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 9605     89/<- %ecx 0/r32/eax
 9606     # var elem-type/edx: type-id = a->right->left->value
 9607     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9608     8b/-> *(eax+4) 2/r32/edx  # Tree-value
 9609     # var array-size/ecx: int = a->right->right->left->value
 9610     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 9611     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9612     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
 9613     # return array-size * size-of(elem-type)
 9614     (size-of-type-id-as-array-element %edx)  # => eax
 9615     f7 4/subop/multiply-into-eax %ecx
 9616     05/add-to-eax 4/imm32  # for array size
 9617 $size-of-array:end:
 9618     # . restore registers
 9619     5a/pop-to-edx
 9620     59/pop-to-ecx
 9621     # . epilogue
 9622     89/<- %esp 5/r32/ebp
 9623     5d/pop-to-ebp
 9624     c3/return
 9625 
 9626 size-of-type-id:  # t: type-id -> result/eax: int
 9627     # . prologue
 9628     55/push-ebp
 9629     89/<- %ebp 4/r32/esp
 9630     # . save registers
 9631     51/push-ecx
 9632     # var out/ecx: (handle typeinfo)
 9633     68/push 0/imm32
 9634     68/push 0/imm32
 9635     89/<- %ecx 4/r32/esp
 9636     # eax = t
 9637     8b/-> *(ebp+8) 0/r32/eax
 9638     # if t is a literal, return 0
 9639     3d/compare-eax-and 0/imm32
 9640     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
 9641     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
 9642     3d/compare-eax-and 8/imm32/byte
 9643     {
 9644       75/jump-if-!= break/disp8
 9645       b8/copy-to-eax 4/imm32
 9646       eb/jump $size-of-type-id:end/disp8
 9647     }
 9648     # if t is a handle, return 8
 9649     3d/compare-eax-and 4/imm32/handle
 9650     {
 9651       75/jump-if-!= break/disp8
 9652       b8/copy-to-eax 8/imm32
 9653       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
 9654     }
 9655     # if t is a user-defined type, return its size
 9656     # TODO: support non-atom type
 9657     (find-typeinfo %eax %ecx)
 9658     {
 9659       81 7/subop/compare *ecx 0/imm32
 9660       74/jump-if-= break/disp8
 9661 $size-of-type-id:user-defined:
 9662       (lookup *ecx *(ecx+4))  # => eax
 9663       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 9664       eb/jump $size-of-type-id:end/disp8
 9665     }
 9666     # otherwise return the word size
 9667     b8/copy-to-eax 4/imm32
 9668 $size-of-type-id:end:
 9669     # . reclaim locals
 9670     81 0/subop/add %esp 8/imm32
 9671     # . restore registers
 9672     59/pop-to-ecx
 9673     # . epilogue
 9674     89/<- %esp 5/r32/ebp
 9675     5d/pop-to-ebp
 9676     c3/return
 9677 
 9678 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
 9679     # . prologue
 9680     55/push-ebp
 9681     89/<- %ebp 4/r32/esp
 9682     # . save registers
 9683     51/push-ecx
 9684     52/push-edx
 9685     53/push-ebx
 9686     # ecx = a
 9687     8b/-> *(ebp+8) 1/r32/ecx
 9688     # edx = b
 9689     8b/-> *(ebp+0xc) 2/r32/edx
 9690 $type-equal?:compare-addr:
 9691     # if (a == b) return true
 9692     8b/-> %ecx 0/r32/eax  # Var-type
 9693     39/compare %edx 0/r32/eax  # Var-type
 9694     b8/copy-to-eax 1/imm32/true
 9695     0f 84/jump-if-= $type-equal?:end/disp32
 9696 $type-equal?:compare-atom-state:
 9697     # if (a->is-atom? != b->is-atom?) return false
 9698     8b/-> *ecx 3/r32/ebx  # Tree-value
 9699     39/compare *edx 3/r32/ebx  # Tree-value
 9700     b8/copy-to-eax 0/imm32/false
 9701     0f 85/jump-if-!= $type-equal?:end/disp32
 9702     # if a->is-atom? return (a->value == b->value)
 9703     {
 9704 $type-equal?:check-atom:
 9705       81 7/subop/compare %ebx 0/imm32/false
 9706       74/jump-if-= break/disp8
 9707 $type-equal?:is-atom:
 9708       8b/-> *(ecx+4) 0/r32/eax  # Tree-value
 9709       39/compare *(edx+4) 0/r32/eax  # Tree-value
 9710       0f 94/set-if-= %al
 9711       81 4/subop/and %eax 0xff/imm32
 9712       e9/jump $type-equal?:end/disp32
 9713     }
 9714 $type-equal?:check-left:
 9715     # if (!type-equal?(a->left, b->left)) return false
 9716     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 9717     89/<- %ebx 0/r32/eax
 9718     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 9719     (type-equal? %eax %ebx)  # => eax
 9720     3d/compare-eax-and 0/imm32/false
 9721     74/jump-if-= $type-equal?:end/disp8
 9722 $type-equal?:check-right:
 9723     # return type-equal?(a->right, b->right)
 9724     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 9725     89/<- %ebx 0/r32/eax
 9726     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 9727     (type-equal? %eax %ebx)  # => eax
 9728 $type-equal?:end:
 9729     # . restore registers
 9730     5b/pop-to-ebx
 9731     5a/pop-to-edx
 9732     59/pop-to-ecx
 9733     # . epilogue
 9734     89/<- %esp 5/r32/ebp
 9735     5d/pop-to-ebp
 9736     c3/return
 9737 
 9738 #######################################################
 9739 # Code-generation
 9740 #######################################################
 9741 
 9742 == data
 9743 
 9744 Curr-block-depth:  # (addr int)
 9745     0/imm32
 9746 Curr-local-stack-offset:  # (addr int)
 9747     0/imm32
 9748 
 9749 == code
 9750 
 9751 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 9752     # . prologue
 9753     55/push-ebp
 9754     89/<- %ebp 4/r32/esp
 9755     # . save registers
 9756     50/push-eax
 9757     # var curr/eax: (addr function) = *Program->functions
 9758     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 9759     {
 9760       # if (curr == null) break
 9761       3d/compare-eax-and 0/imm32
 9762       0f 84/jump-if-= break/disp32
 9763       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
 9764       # curr = lookup(curr->next)
 9765       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 9766       e9/jump loop/disp32
 9767     }
 9768 $emit-subx:end:
 9769     # . restore registers
 9770     58/pop-to-eax
 9771     # . epilogue
 9772     89/<- %esp 5/r32/ebp
 9773     5d/pop-to-ebp
 9774     c3/return
 9775 
 9776 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9777     # . prologue
 9778     55/push-ebp
 9779     89/<- %ebp 4/r32/esp
 9780     # some preprocessing
 9781     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
 9782     # . save registers
 9783     50/push-eax
 9784     51/push-ecx
 9785     52/push-edx
 9786     57/push-edi
 9787     # initialize some global state
 9788     c7 0/subop/copy *Curr-block-depth 1/imm32
 9789     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
 9790     # ecx = f
 9791     8b/-> *(ebp+0xc) 1/r32/ecx
 9792     # var vars/edx: (stack (addr var) 256)
 9793     81 5/subop/subtract %esp 0xc00/imm32
 9794     68/push 0xc00/imm32/size
 9795     68/push 0/imm32/top
 9796     89/<- %edx 4/r32/esp
 9797     # var name/eax: (addr array byte) = lookup(f->name)
 9798     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 9799     #
 9800     (write-buffered *(ebp+8) %eax)
 9801     (write-buffered *(ebp+8) ":\n")
 9802     (emit-subx-prologue *(ebp+8))
 9803     # var outputs/edi: (addr list var) = lookup(f->outputs)
 9804     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9805     89/<- %edi 0/r32/eax
 9806     # var body/eax: (addr block) = lookup(f->body)
 9807     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
 9808     #
 9809     (emit-subx-block *(ebp+8) %eax %edx %edi *(ebp+0x10) *(ebp+0x14))
 9810     (emit-subx-epilogue *(ebp+8))
 9811     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
 9812     # been cleaned up
 9813 $emit-subx-function:end:
 9814     # . reclaim locals
 9815     81 0/subop/add %esp 0xc08/imm32
 9816     # . restore registers
 9817     5f/pop-to-edi
 9818     5a/pop-to-edx
 9819     59/pop-to-ecx
 9820     58/pop-to-eax
 9821     # . epilogue
 9822     89/<- %esp 5/r32/ebp
 9823     5d/pop-to-ebp
 9824     c3/return
 9825 
 9826 populate-mu-type-offsets-in-inouts:  # f: (addr function)
 9827     # . prologue
 9828     55/push-ebp
 9829     89/<- %ebp 4/r32/esp
 9830     # . save registers
 9831     50/push-eax
 9832     51/push-ecx
 9833     52/push-edx
 9834     53/push-ebx
 9835     57/push-edi
 9836     # var next-offset/edx: int = 8
 9837     ba/copy-to-edx 8/imm32
 9838     # var curr/ecx: (addr list var) = lookup(f->inouts)
 9839     8b/-> *(ebp+8) 1/r32/ecx
 9840     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 9841     89/<- %ecx 0/r32/eax
 9842     {
 9843 $populate-mu-type-offsets-in-inouts:loop:
 9844       81 7/subop/compare %ecx 0/imm32
 9845       74/jump-if-= break/disp8
 9846       # var v/ebx: (addr var) = lookup(curr->value)
 9847       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9848       89/<- %ebx 0/r32/eax
 9849 #?       (lookup *ebx *(ebx+4))
 9850 #?       (write-buffered Stderr "setting offset of fn inout ")
 9851 #?       (write-buffered Stderr %eax)
 9852 #?       (write-buffered Stderr "@")
 9853 #?       (print-int32-buffered Stderr %ebx)
 9854 #?       (write-buffered Stderr " to ")
 9855 #?       (print-int32-buffered Stderr %edx)
 9856 #?       (write-buffered Stderr Newline)
 9857 #?       (flush Stderr)
 9858       # v->offset = next-offset
 9859       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
 9860       # next-offset += size-of(v)
 9861       (size-of %ebx)  # => eax
 9862       01/add-to %edx 0/r32/eax
 9863       # curr = lookup(curr->next)
 9864       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9865       89/<- %ecx 0/r32/eax
 9866       #
 9867       eb/jump loop/disp8
 9868     }
 9869 $populate-mu-type-offsets-in-inouts:end:
 9870     # . restore registers
 9871     5f/pop-to-edi
 9872     5b/pop-to-ebx
 9873     5a/pop-to-edx
 9874     59/pop-to-ecx
 9875     58/pop-to-eax
 9876     # . epilogue
 9877     89/<- %esp 5/r32/ebp
 9878     5d/pop-to-ebp
 9879     c3/return
 9880 
 9881 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9882     # . prologue
 9883     55/push-ebp
 9884     89/<- %ebp 4/r32/esp
 9885     # . save registers
 9886     50/push-eax
 9887     51/push-ecx
 9888     53/push-ebx
 9889     56/push-esi
 9890     # esi = stmts
 9891     8b/-> *(ebp+0xc) 6/r32/esi
 9892     #
 9893     {
 9894 $emit-subx-stmt-list:loop:
 9895       81 7/subop/compare %esi 0/imm32
 9896       0f 84/jump-if-= break/disp32
 9897       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
 9898       (lookup *esi *(esi+4))  # List-value List-value => eax
 9899       89/<- %ecx 0/r32/eax
 9900       {
 9901 $emit-subx-stmt-list:check-for-block:
 9902         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 9903         75/jump-if-!= break/disp8
 9904 $emit-subx-stmt-list:block:
 9905         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 9906       }
 9907       {
 9908 $emit-subx-stmt-list:check-for-stmt:
 9909         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 9910         0f 85/jump-if-!= break/disp32
 9911 $emit-subx-stmt-list:stmt1:
 9912         {
 9913           (is-mu-branch? %ecx)  # => eax
 9914           3d/compare-eax-and 0/imm32/false
 9915           0f 84/jump-if-= break/disp32
 9916 $emit-subx-stmt-list:branch-stmt:
 9917 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
 9944 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
 9960 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
 9998 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
10017         }
10018 $emit-subx-stmt-list:1-to-1:
10019         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
10020         e9/jump $emit-subx-stmt-list:continue/disp32
10021       }
10022       {
10023 $emit-subx-stmt-list:check-for-var-def:
10024         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
10025         75/jump-if-!= break/disp8
10026 $emit-subx-stmt-list:var-def:
10027         (emit-subx-var-def *(ebp+8) %ecx)
10028         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
10029         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
10030         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
10031         #
10032         eb/jump $emit-subx-stmt-list:continue/disp8
10033       }
10034       {
10035 $emit-subx-stmt-list:check-for-reg-var-def:
10036         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
10037         0f 85/jump-if-!= break/disp32
10038 $emit-subx-stmt-list:reg-var-def:
10039         # TODO: ensure that there's exactly one output
10040         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10041         # emit the instruction as usual
10042         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
10043         #
10044         eb/jump $emit-subx-stmt-list:continue/disp8
10045       }
10046 $emit-subx-stmt-list:continue:
10047       # TODO: raise an error on unrecognized Stmt-tag
10048       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
10049       89/<- %esi 0/r32/eax
10050       e9/jump loop/disp32
10051     }
10052 $emit-subx-stmt-list:emit-cleanup:
10053     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
10054 $emit-subx-stmt-list:clean-up:
10055     (clean-up-blocks *(ebp+0x10) *Curr-block-depth)
10056 $emit-subx-stmt-list:end:
10057     # . restore registers
10058     5e/pop-to-esi
10059     5b/pop-to-ebx
10060     59/pop-to-ecx
10061     58/pop-to-eax
10062     # . epilogue
10063     89/<- %esp 5/r32/ebp
10064     5d/pop-to-ebp
10065     c3/return
10066 
10067 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
10068 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-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
10069     # . prologue
10070     55/push-ebp
10071     89/<- %ebp 4/r32/esp
10072     # . save registers
10073     50/push-eax
10074     51/push-ecx
10075     52/push-edx
10076     # ecx = stmt
10077     8b/-> *(ebp+0xc) 1/r32/ecx
10078     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
10079     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10080     # TODO: assert !sv->is-deref?
10081     # var v/ecx: (addr var) = lookup(sv->value)
10082     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10083     89/<- %ecx 0/r32/eax
10084     # v->block-depth = *Curr-block-depth
10085     8b/-> *Curr-block-depth 0/r32/eax
10086     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10087 #?     (write-buffered Stderr "var ")
10088 #?     (lookup *ecx *(ecx+4))
10089 #?     (write-buffered Stderr %eax)
10090 #?     (write-buffered Stderr " at depth ")
10091 #?     (print-int32-buffered Stderr *(ecx+0x10))
10092 #?     (write-buffered Stderr Newline)
10093 #?     (flush Stderr)
10094     # ensure that v is in a register
10095     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
10096     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
10097     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn-outputs)
10098     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
10099     89/<- %edx 0/r32/eax
10100     3d/compare-eax-and 0/imm32/false
10101     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
10102     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
10103     89/<- %edx 0/r32/eax
10104     # check emit-spill?
10105     3d/compare-eax-and 0/imm32/false
10106     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
10107     # TODO: assert(size-of(output) == 4)
10108     # *Curr-local-stack-offset -= 4
10109     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
10110     # emit spill
10111     (emit-indent *(ebp+8) *Curr-block-depth)
10112     (write-buffered *(ebp+8) "ff 6/subop/push %")
10113     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10114     (write-buffered *(ebp+8) %eax)
10115     (write-buffered *(ebp+8) Newline)
10116 $push-output-and-maybe-emit-spill:push:
10117     8b/-> *(ebp+0xc) 1/r32/ecx
10118     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
10119     # push(vars, {sv->value, emit-spill?})
10120     (push *(ebp+0x10) *eax)  # Stmt-var-value
10121     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
10122     (push *(ebp+0x10) %edx)
10123 $push-output-and-maybe-emit-spill:end:
10124     # . restore registers
10125     5a/pop-to-edx
10126     59/pop-to-ecx
10127     58/pop-to-eax
10128     # . epilogue
10129     89/<- %esp 5/r32/ebp
10130     5d/pop-to-ebp
10131     c3/return
10132 
10133 $push-output-and-maybe-emit-spill:abort:
10134     # error("var '" var->name "' initialized from an instruction must live in a register\n")
10135     (write-buffered *(ebp+0x1c) "var '")
10136     (write-buffered *(ebp+0x1c) *eax)  # Var-name
10137     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
10138     (flush *(ebp+0x1c))
10139     (stop *(ebp+0x20) 1)
10140     # never gets here
10141 
10142 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
10143     # . prologue
10144     55/push-ebp
10145     89/<- %ebp 4/r32/esp
10146     # . save registers
10147     50/push-eax
10148     51/push-ecx
10149     # ecx = stmt
10150     8b/-> *(ebp+0xc) 1/r32/ecx
10151     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
10152     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10153     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10154     (lookup *eax *(eax+4))  # Var-name Var-name => eax
10155     # clean up until target block
10156     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
10157     # emit jump to target block
10158     (emit-indent *(ebp+8) *Curr-block-depth)
10159     (write-buffered *(ebp+8) "e9/jump ")
10160     (write-buffered *(ebp+8) %eax)
10161     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
10162     (string-starts-with? %eax "break")
10163     3d/compare-eax-and 0/imm32/false
10164     {
10165       74/jump-if-= break/disp8
10166       (write-buffered *(ebp+8) ":break/disp32\n")
10167     }
10168     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
10169     {
10170       75/jump-if-!= break/disp8
10171       (write-buffered *(ebp+8) ":loop/disp32\n")
10172     }
10173 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
10174     # . restore registers
10175     59/pop-to-ecx
10176     58/pop-to-eax
10177     # . epilogue
10178     89/<- %esp 5/r32/ebp
10179     5d/pop-to-ebp
10180     c3/return
10181 
10182 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
10183     # . prologue
10184     55/push-ebp
10185     89/<- %ebp 4/r32/esp
10186     # . save registers
10187     51/push-ecx
10188     # ecx = lookup(stmt->operation)
10189     8b/-> *(ebp+8) 1/r32/ecx
10190     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
10191     89/<- %ecx 0/r32/eax
10192     # if (stmt->operation starts with "loop") return true
10193     (string-starts-with? %ecx "loop")  # => eax
10194     3d/compare-eax-and 0/imm32/false
10195     75/jump-if-not-equal $is-mu-branch?:end/disp8
10196     # otherwise return (stmt->operation starts with "break")
10197     (string-starts-with? %ecx "break")  # => eax
10198 $is-mu-branch?:end:
10199     # . restore registers
10200     59/pop-to-ecx
10201     # . epilogue
10202     89/<- %esp 5/r32/ebp
10203     5d/pop-to-ebp
10204     c3/return
10205 
10206 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
10207     # . prologue
10208     55/push-ebp
10209     89/<- %ebp 4/r32/esp
10210     # . save registers
10211     50/push-eax
10212     # eax = stmt
10213     8b/-> *(ebp+0xc) 0/r32/eax
10214     #
10215     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
10216     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
10217     (emit-indent *(ebp+8) *Curr-block-depth)
10218     (lookup *eax *(eax+4))  # => eax
10219     (write-buffered *(ebp+8) %eax)
10220     (write-buffered *(ebp+8) " break/disp32\n")
10221 $emit-reverse-break:end:
10222     # . restore registers
10223     58/pop-to-eax
10224     # . epilogue
10225     89/<- %esp 5/r32/ebp
10226     5d/pop-to-ebp
10227     c3/return
10228 
10229 == data
10230 
10231 # Table from Mu branch instructions to the reverse SubX opcodes for them.
10232 Reverse-branch:  # (table (handle array byte) (handle array byte))
10233   # a table is a stream
10234   0x140/imm32/write
10235   0/imm32/read
10236   0x140/imm32/size
10237   # data
10238   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
10239   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
10240   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
10241   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
10242   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
10243   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
10244   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
10245   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
10246   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10247   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10248   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
10249   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
10250   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
10251   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
10252   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
10253   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
10254   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10255   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
10256   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
10257   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
10258 
10259 == code
10260 
10261 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
10262     # . prologue
10263     55/push-ebp
10264     89/<- %ebp 4/r32/esp
10265     # . save registers
10266     50/push-eax
10267     51/push-ecx
10268     52/push-edx
10269     53/push-ebx
10270     56/push-esi
10271     # ecx = vars
10272     8b/-> *(ebp+0xc) 1/r32/ecx
10273     # var eax: int = vars->top
10274     8b/-> *ecx 0/r32/eax
10275     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10276     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
10277     # var min/ecx: (addr handle var) = vars->data
10278     8d/copy-address *(ecx+8) 1/r32/ecx
10279     # edx = depth
10280     8b/-> *(ebp+0x10) 2/r32/edx
10281     {
10282 $emit-unconditional-jump-to-depth:loop:
10283       # if (curr < min) break
10284       39/compare %esi 1/r32/ecx
10285       0f 82/jump-if-addr< break/disp32
10286       # var v/ebx: (addr var) = lookup(*curr)
10287       (lookup *esi *(esi+4))  # => eax
10288       89/<- %ebx 0/r32/eax
10289       # if (v->block-depth < until-block-depth) break
10290       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
10291       0f 8c/jump-if-< break/disp32
10292       {
10293 $emit-unconditional-jump-to-depth:check:
10294         # if v->block-depth != until-block-depth, continue
10295         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
10296         0f 85/jump-if-!= break/disp32
10297 $emit-unconditional-jump-to-depth:depth-found:
10298         # if v is not a literal, continue
10299         (size-of %ebx)  # => eax
10300         3d/compare-eax-and 0/imm32
10301         0f 85/jump-if-!= break/disp32
10302 $emit-unconditional-jump-to-depth:label-found:
10303         # emit unconditional jump, then return
10304         (emit-indent *(ebp+8) *Curr-block-depth)
10305         (write-buffered *(ebp+8) "e9/jump ")
10306         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
10307         (write-buffered *(ebp+8) %eax)
10308         (write-buffered *(ebp+8) ":")
10309         (write-buffered *(ebp+8) *(ebp+0x14))
10310         (write-buffered *(ebp+8) "/disp32\n")
10311         eb/jump $emit-unconditional-jump-to-depth:end/disp8
10312       }
10313       # curr -= 12
10314       81 5/subop/subtract %esi 0xc/imm32
10315       e9/jump loop/disp32
10316     }
10317     # TODO: error if no label at 'depth' was found
10318 $emit-unconditional-jump-to-depth:end:
10319     # . restore registers
10320     5e/pop-to-esi
10321     5b/pop-to-ebx
10322     5a/pop-to-edx
10323     59/pop-to-ecx
10324     58/pop-to-eax
10325     # . epilogue
10326     89/<- %esp 5/r32/ebp
10327     5d/pop-to-ebp
10328     c3/return
10329 
10330 # emit clean-up code for 'vars' until some block depth
10331 # doesn't actually modify 'vars' so we need traverse manually inside the stack
10332 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
10333     # . prologue
10334     55/push-ebp
10335     89/<- %ebp 4/r32/esp
10336     # . save registers
10337     50/push-eax
10338     51/push-ecx
10339     52/push-edx
10340     53/push-ebx
10341     56/push-esi
10342 #?     (write-buffered Stderr "--- cleanup\n")
10343 #?     (flush Stderr)
10344     # ecx = vars
10345     8b/-> *(ebp+0xc) 1/r32/ecx
10346     # var esi: int = vars->top
10347     8b/-> *ecx 6/r32/esi
10348     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
10349     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
10350     # var min/ecx: (addr handle var) = vars->data
10351     81 0/subop/add %ecx 8/imm32
10352     # edx = until-block-depth
10353     8b/-> *(ebp+0x10) 2/r32/edx
10354     {
10355 $emit-cleanup-code-until-depth:loop:
10356       # if (curr < min) break
10357       39/compare %esi 1/r32/ecx
10358       0f 82/jump-if-addr< break/disp32
10359       # var v/ebx: (addr var) = lookup(*curr)
10360       (lookup *esi *(esi+4))  # => eax
10361       89/<- %ebx 0/r32/eax
10362 #?       (lookup *ebx *(ebx+4))  # Var-name
10363 #?       (write-buffered Stderr "var ")
10364 #?       (write-buffered Stderr %eax)
10365 #?       (write-buffered Stderr Newline)
10366 #?       (flush Stderr)
10367       # if (v->block-depth < until-block-depth) break
10368       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
10369       0f 8c/jump-if-< break/disp32
10370       # if v is in a register
10371       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
10372       {
10373         0f 84/jump-if-= break/disp32
10374         {
10375 $emit-cleanup-code-until-depth:check-for-previous-spill:
10376           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
10377           3d/compare-eax-and 0/imm32/false
10378           74/jump-if-= break/disp8
10379 $emit-cleanup-code-until-depth:reclaim-var-in-register:
10380           (emit-indent *(ebp+8) *Curr-block-depth)
10381           (write-buffered *(ebp+8) "8f 0/subop/pop %")
10382           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
10383           (write-buffered *(ebp+8) %eax)
10384           (write-buffered *(ebp+8) Newline)
10385         }
10386         eb/jump $emit-cleanup-code-until-depth:continue/disp8
10387       }
10388       # otherwise v is on the stack
10389       {
10390         75/jump-if-!= break/disp8
10391 $emit-cleanup-code-until-depth:var-on-stack:
10392         (size-of %ebx)  # => eax
10393         # don't emit code for labels
10394         3d/compare-eax-and 0/imm32
10395         74/jump-if-= break/disp8
10396 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
10397         (emit-indent *(ebp+8) *Curr-block-depth)
10398         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
10399         (print-int32-buffered *(ebp+8) %eax)
10400         (write-buffered *(ebp+8) "/imm32\n")
10401       }
10402 $emit-cleanup-code-until-depth:continue:
10403       # curr -= 12
10404       81 5/subop/subtract %esi 0xc/imm32
10405       e9/jump loop/disp32
10406     }
10407 $emit-cleanup-code-until-depth:end:
10408     # . restore registers
10409     5e/pop-to-esi
10410     5b/pop-to-ebx
10411     5a/pop-to-edx
10412     59/pop-to-ecx
10413     58/pop-to-eax
10414     # . epilogue
10415     89/<- %esp 5/r32/ebp
10416     5d/pop-to-ebp
10417     c3/return
10418 
10419 # emit clean-up code for 'vars' until a given label is encountered
10420 # doesn't actually modify 'vars' so we need traverse manually inside the stack
10421 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
10422     # . prologue
10423     55/push-ebp
10424     89/<- %ebp 4/r32/esp
10425     # . save registers
10426     50/push-eax
10427     51/push-ecx
10428     52/push-edx
10429     53/push-ebx
10430     # ecx = vars
10431     8b/-> *(ebp+0xc) 1/r32/ecx
10432     # var eax: int = vars->top
10433     8b/-> *ecx 0/r32/eax
10434     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
10435     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
10436     # var min/ecx: (addr handle var) = vars->data
10437     81 0/subop/add %ecx 8/imm32
10438     {
10439 $emit-cleanup-code-until-target:loop:
10440       # if (curr < min) break
10441       39/compare %edx 1/r32/ecx
10442       0f 82/jump-if-addr< break/disp32
10443       # var v/ebx: (handle var) = lookup(*curr)
10444       (lookup *edx *(edx+4))  # => eax
10445       89/<- %ebx 0/r32/eax
10446       # if (v->name == until-block-label) break
10447       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
10448       (string-equal? %eax *(ebp+0x10))  # => eax
10449       3d/compare-eax-and 0/imm32/false
10450       0f 85/jump-if-!= break/disp32
10451       # if v is in a register
10452       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
10453       {
10454         0f 84/jump-if-= break/disp32
10455         {
10456 $emit-cleanup-code-until-target:check-for-previous-spill:
10457           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
10458           3d/compare-eax-and 0/imm32/false
10459           74/jump-if-= break/disp8
10460 $emit-cleanup-code-until-target:reclaim-var-in-register:
10461           (emit-indent *(ebp+8) *Curr-block-depth)
10462           (write-buffered *(ebp+8) "8f 0/subop/pop %")
10463           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
10464           (write-buffered *(ebp+8) %eax)
10465           (write-buffered *(ebp+8) Newline)
10466         }
10467         eb/jump $emit-cleanup-code-until-target:continue/disp8
10468       }
10469       # otherwise v is on the stack
10470       {
10471         75/jump-if-!= break/disp8
10472 $emit-cleanup-code-until-target:reclaim-var-on-stack:
10473         (size-of %ebx)  # => eax
10474         # don't emit code for labels
10475         3d/compare-eax-and 0/imm32
10476         74/jump-if-= break/disp8
10477         #
10478         (emit-indent *(ebp+8) *Curr-block-depth)
10479         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
10480         (print-int32-buffered *(ebp+8) %eax)
10481         (write-buffered *(ebp+8) "/imm32\n")
10482       }
10483 $emit-cleanup-code-until-target:continue:
10484       # curr -= 12
10485       81 5/subop/subtract %edx 0xc/imm32
10486       e9/jump loop/disp32
10487     }
10488 $emit-cleanup-code-until-target:end:
10489     # . restore registers
10490     5b/pop-to-ebx
10491     5a/pop-to-edx
10492     59/pop-to-ecx
10493     58/pop-to-eax
10494     # . epilogue
10495     89/<- %esp 5/r32/ebp
10496     5d/pop-to-ebp
10497     c3/return
10498 
10499 # Return true if there isn't a variable in 'vars' with the same block-depth
10500 # and register as 'v'.
10501 # 'v' is guaranteed not to be within 'vars'.
10502 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
10503     # . prologue
10504     55/push-ebp
10505     89/<- %ebp 4/r32/esp
10506     # . save registers
10507     51/push-ecx
10508     52/push-edx
10509     53/push-ebx
10510     56/push-esi
10511     57/push-edi
10512     # ecx = vars
10513     8b/-> *(ebp+0xc) 1/r32/ecx
10514     # var eax: int = vars->top
10515     8b/-> *ecx 0/r32/eax
10516     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
10517     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
10518     # var min/ecx: (addr handle var) = vars->data
10519     8d/copy-address *(ecx+8) 1/r32/ecx
10520     # var depth/ebx: int = v->block-depth
10521     8b/-> *(ebp+8) 3/r32/ebx
10522     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
10523     # var needle/esi: (addr array byte) = v->register
10524     8b/-> *(ebp+8) 6/r32/esi
10525     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
10526     89/<- %esi 0/r32/eax
10527     {
10528 $not-yet-spilled-this-block?:loop:
10529       # if (curr < min) break
10530       39/compare %edx 1/r32/ecx
10531       0f 82/jump-if-addr< break/disp32
10532       # var cand/edi: (addr var) = lookup(*curr)
10533       (lookup *edx *(edx+4))  # => eax
10534       89/<- %edi 0/r32/eax
10535       # if (cand->block-depth < depth) break
10536       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
10537       0f 8c/jump-if-< break/disp32
10538       # var cand-reg/edi: (array array byte) = cand->reg
10539       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
10540       89/<- %edi 0/r32/eax
10541       # if (cand-reg == null) continue
10542       {
10543 $not-yet-spilled-this-block?:check-reg:
10544         81 7/subop/compare %edi 0/imm32
10545         0f 84/jump-if-= break/disp32
10546         # if (cand-reg == needle) return true
10547         (string-equal? %esi %edi)  # => eax
10548         3d/compare-eax-and 0/imm32/false
10549         74/jump-if-= break/disp8
10550 $not-yet-spilled-this-block?:return-false:
10551         b8/copy-to-eax 0/imm32/false
10552         eb/jump $not-yet-spilled-this-block?:end/disp8
10553       }
10554 $not-yet-spilled-this-block?:continue:
10555       # curr -= 12
10556       81 5/subop/subtract %edx 0xc/imm32
10557       e9/jump loop/disp32
10558     }
10559 $not-yet-spilled-this-block?:return-true:
10560     # return true
10561     b8/copy-to-eax 1/imm32/true
10562 $not-yet-spilled-this-block?:end:
10563     # . restore registers
10564     5f/pop-to-edi
10565     5e/pop-to-esi
10566     5b/pop-to-ebx
10567     5a/pop-to-edx
10568     59/pop-to-ecx
10569     # . epilogue
10570     89/<- %esp 5/r32/ebp
10571     5d/pop-to-ebp
10572     c3/return
10573 
10574 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
10575 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn-outputs: (addr list var) -> result/eax: boolean
10576     # . prologue
10577     55/push-ebp
10578     89/<- %ebp 4/r32/esp
10579     # eax = v
10580     8b/-> *(ebp+8) 0/r32/eax
10581     # var reg/eax: (addr array byte) = lookup(v->register)
10582     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10583     # var target/eax: (addr var) = find-register(fn-outputs, reg)
10584     (find-register *(ebp+0x10) %eax)  # => eax
10585     # if (target == 0) return true
10586     {
10587       3d/compare-eax-and 0/imm32
10588       75/jump-if-!= break/disp8
10589       b8/copy-to-eax 1/imm32/true
10590       eb/jump $will-not-write-some-register?:end/disp8
10591     }
10592     # return !assigns-in-stmts?(stmts, target)
10593     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
10594     3d/compare-eax-and 0/imm32/false
10595     # assume: true = 1, so no need to mask with 0x000000ff
10596     0f 94/set-if-= %al
10597 $will-not-write-some-register?:end:
10598     # . epilogue
10599     89/<- %esp 5/r32/ebp
10600     5d/pop-to-ebp
10601     c3/return
10602 
10603 # return output var with matching register
10604 # always returns false if 'reg' is null
10605 find-register:  # fn-outputs: (addr list var), reg: (addr array byte) -> result/eax: (addr var)
10606     # . prologue
10607     55/push-ebp
10608     89/<- %ebp 4/r32/esp
10609     # . save registers
10610     51/push-ecx
10611     # var curr/ecx: (addr list var) = fn-outputs
10612     8b/-> *(ebp+8) 1/r32/ecx
10613     {
10614 $find-register:loop:
10615       # if (curr == 0) break
10616       81 7/subop/compare %ecx 0/imm32
10617       74/jump-if-= break/disp8
10618       # eax = curr->value->register
10619       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10620       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10621       # if (eax == reg) return curr->value
10622 $find-register:compare:
10623       (string-equal? *(ebp+0xc) %eax)  # => eax
10624       {
10625         3d/compare-eax-and 0/imm32/false
10626         74/jump-if-= break/disp8
10627 $find-register:found:
10628         (lookup *ecx *(ecx+4))  # List-value List-value => eax
10629         eb/jump $find-register:end/disp8
10630       }
10631       # curr = lookup(curr->next)
10632       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10633       89/<- %ecx 0/r32/eax
10634       #
10635       eb/jump loop/disp8
10636     }
10637 $find-register:end:
10638     # . restore registers
10639     59/pop-to-ecx
10640     # . epilogue
10641     89/<- %esp 5/r32/ebp
10642     5d/pop-to-ebp
10643     c3/return
10644 
10645 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
10646     # . prologue
10647     55/push-ebp
10648     89/<- %ebp 4/r32/esp
10649     # . save registers
10650     51/push-ecx
10651     # var curr/ecx: (addr list stmt) = stmts
10652     8b/-> *(ebp+8) 1/r32/ecx
10653     {
10654       # if (curr == 0) break
10655       81 7/subop/compare %ecx 0/imm32
10656       74/jump-if-= break/disp8
10657       # if assigns-in-stmt?(curr->value, v) return true
10658       (lookup *ecx *(ecx+4))  # List-value List-value => eax
10659       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
10660       3d/compare-eax-and 0/imm32/false
10661       75/jump-if-!= break/disp8
10662       # curr = lookup(curr->next)
10663       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
10664       89/<- %ecx 0/r32/eax
10665       #
10666       eb/jump loop/disp8
10667     }
10668 $assigns-in-stmts?:end:
10669     # . restore registers
10670     59/pop-to-ecx
10671     # . epilogue
10672     89/<- %esp 5/r32/ebp
10673     5d/pop-to-ebp
10674     c3/return
10675 
10676 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
10677     # . prologue
10678     55/push-ebp
10679     89/<- %ebp 4/r32/esp
10680     # . save registers
10681     51/push-ecx
10682     # ecx = stmt
10683     8b/-> *(ebp+8) 1/r32/ecx
10684     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
10685     {
10686       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
10687       75/jump-if-!= break/disp8
10688       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10689       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
10690       eb/jump $assigns-in-stmt?:end/disp8
10691     }
10692     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
10693     {
10694       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
10695       75/jump-if-!= break/disp8
10696       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
10697       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
10698       eb/jump $assigns-in-stmt?:end/disp8
10699     }
10700     # otherwise return false
10701     b8/copy 0/imm32/false
10702 $assigns-in-stmt?:end:
10703     # . restore registers
10704     59/pop-to-ecx
10705     # . epilogue
10706     89/<- %esp 5/r32/ebp
10707     5d/pop-to-ebp
10708     c3/return
10709 
10710 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
10711     # . prologue
10712     55/push-ebp
10713     89/<- %ebp 4/r32/esp
10714     # . save registers
10715     51/push-ecx
10716     # var curr/ecx: (addr stmt-var) = stmt-var
10717     8b/-> *(ebp+8) 1/r32/ecx
10718     {
10719       # if (curr == 0) break
10720       81 7/subop/compare %ecx 0/imm32
10721       74/jump-if-= break/disp8
10722       # eax = lookup(curr->value)
10723       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
10724       # if (eax == v  &&  curr->is-deref? == false) return true
10725       {
10726         39/compare *(ebp+0xc) 0/r32/eax
10727         75/jump-if-!= break/disp8
10728         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
10729         75/jump-if-!= break/disp8
10730         b8/copy-to-eax 1/imm32/true
10731         eb/jump $assigns-in-stmt-vars?:end/disp8
10732       }
10733       # curr = lookup(curr->next)
10734       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
10735       89/<- %ecx 0/r32/eax
10736       #
10737       eb/jump loop/disp8
10738     }
10739 $assigns-in-stmt-vars?:end:
10740     # . restore registers
10741     59/pop-to-ecx
10742     # . epilogue
10743     89/<- %esp 5/r32/ebp
10744     5d/pop-to-ebp
10745     c3/return
10746 
10747 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
10748 # v is guaranteed to be within vars
10749 # 'start' is provided as an optimization, a pointer within vars
10750 # *start == v
10751 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
10752     # . prologue
10753     55/push-ebp
10754     89/<- %ebp 4/r32/esp
10755     # . save registers
10756     51/push-ecx
10757     52/push-edx
10758     53/push-ebx
10759     56/push-esi
10760     57/push-edi
10761     # ecx = v
10762     8b/-> *(ebp+8) 1/r32/ecx
10763     # var reg/edx: (addr array byte) = lookup(v->register)
10764     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
10765     89/<- %edx 0/r32/eax
10766     # var depth/ebx: int = v->block-depth
10767     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
10768     # var min/ecx: (addr handle var) = vars->data
10769     8b/-> *(ebp+0xc) 1/r32/ecx
10770     81 0/subop/add %ecx 8/imm32
10771     # TODO: check that start >= min and start < &vars->data[top]
10772     # TODO: check that *start == v
10773     # var curr/esi: (addr handle var) = start
10774     8b/-> *(ebp+0x10) 6/r32/esi
10775     # curr -= 8
10776     81 5/subop/subtract %esi 8/imm32
10777     {
10778 $same-register-spilled-before?:loop:
10779       # if (curr < min) break
10780       39/compare %esi 1/r32/ecx
10781       0f 82/jump-if-addr< break/disp32
10782       # var x/eax: (addr var) = lookup(*curr)
10783       (lookup *esi *(esi+4))  # => eax
10784       # if (x->block-depth < depth) break
10785       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
10786       0f 8c/jump-if-< break/disp32
10787       # if (x->register == 0) continue
10788       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
10789       74/jump-if-= $same-register-spilled-before?:continue/disp8
10790       # if (x->register == reg) return true
10791       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10792       (string-equal? %eax %edx)  # => eax
10793       3d/compare-eax-and 0/imm32/false
10794       b8/copy-to-eax 1/imm32/true
10795       75/jump-if-!= $same-register-spilled-before?:end/disp8
10796 $same-register-spilled-before?:continue:
10797       # curr -= 8
10798       81 5/subop/subtract %esi 8/imm32
10799       e9/jump loop/disp32
10800     }
10801 $same-register-spilled-before?:false:
10802     b8/copy-to-eax 0/imm32/false
10803 $same-register-spilled-before?:end:
10804     # . restore registers
10805     5f/pop-to-edi
10806     5e/pop-to-esi
10807     5b/pop-to-ebx
10808     5a/pop-to-edx
10809     59/pop-to-ecx
10810     # . epilogue
10811     89/<- %esp 5/r32/ebp
10812     5d/pop-to-ebp
10813     c3/return
10814 
10815 # clean up global state for 'vars' until some block depth
10816 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int
10817     # . prologue
10818     55/push-ebp
10819     89/<- %ebp 4/r32/esp
10820     # . save registers
10821     50/push-eax
10822     51/push-ecx
10823     56/push-esi
10824     # esi = vars
10825     8b/-> *(ebp+8) 6/r32/esi
10826     # ecx = until-block-depth
10827     8b/-> *(ebp+0xc) 1/r32/ecx
10828     {
10829 $clean-up-blocks:reclaim-loop:
10830       # if (vars->top <= 0) break
10831       8b/-> *esi 0/r32/eax  # Stack-top
10832       3d/compare-eax-and 0/imm32
10833       0f 8e/jump-if-<= break/disp32
10834       # var v/eax: (addr var) = lookup(vars[vars->top-12])
10835 #?       (print-int32-buffered Stderr %eax)
10836 #?       (write-buffered Stderr ": ")
10837 #?       (print-int32-buffered Stderr *(esi+eax-4))
10838 #?       (write-buffered Stderr " ")
10839 #?       (print-int32-buffered Stderr *(esi+eax))
10840 #?       (write-buffered Stderr " ")
10841 #?       (print-int32-buffered Stderr *(esi+eax+4))
10842 #?       (write-buffered Stderr Newline)
10843 #?       (flush Stderr)
10844       (lookup *(esi+eax-4) *(esi+eax))  # vars + 8 + vars->top - 12 => eax
10845       # if (v->block-depth < until-block-depth) break
10846       39/compare *(eax+0x10) 1/r32/ecx  # Var-block-depth
10847       7c/jump-if-< break/disp8
10848       # if v is on the stack, update Curr-local-stack-offset
10849       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
10850       {
10851         75/jump-if-!= break/disp8
10852 $clean-up-blocks:reclaim-var-on-stack:
10853         (size-of %eax)  # => eax
10854         01/add-to *Curr-local-stack-offset 0/r32/eax
10855       }
10856       (pop %esi)  # => eax
10857       (pop %esi)  # => eax
10858       (pop %esi)  # => eax
10859       e9/jump loop/disp32
10860     }
10861 $clean-up-blocks:end:
10862     # . restore registers
10863     5e/pop-to-esi
10864     59/pop-to-ecx
10865     58/pop-to-eax
10866     # . epilogue
10867     89/<- %esp 5/r32/ebp
10868     5d/pop-to-ebp
10869     c3/return
10870 
10871 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
10872     # . prologue
10873     55/push-ebp
10874     89/<- %ebp 4/r32/esp
10875     # . save registers
10876     50/push-eax
10877     51/push-ecx
10878     52/push-edx
10879     # eax = stmt
10880     8b/-> *(ebp+0xc) 0/r32/eax
10881     # var v/ecx: (addr var)
10882     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
10883     89/<- %ecx 0/r32/eax
10884     # v->block-depth = *Curr-block-depth
10885     8b/-> *Curr-block-depth 0/r32/eax
10886     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
10887     # var n/edx: int = size-of(stmt->var)
10888     (size-of %ecx)  # => eax
10889     89/<- %edx 0/r32/eax
10890     # *Curr-local-stack-offset -= n
10891     29/subtract-from *Curr-local-stack-offset 2/r32/edx
10892     # v->offset = *Curr-local-stack-offset
10893     8b/-> *Curr-local-stack-offset 0/r32/eax
10894     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
10895     # if v is an array, do something special
10896     {
10897       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10898       (is-mu-array? %eax)  # => eax
10899       3d/compare-eax-and 0/imm32/false
10900       0f 84/jump-if-= break/disp32
10901       # var array-size-without-size/edx: int = n-4
10902       81 5/subop/subtract %edx 4/imm32
10903       (emit-indent *(ebp+8) *Curr-block-depth)
10904       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
10905       (print-int32-buffered *(ebp+8) %edx)
10906       (write-buffered *(ebp+8) ")\n")
10907       (emit-indent *(ebp+8) *Curr-block-depth)
10908       (write-buffered *(ebp+8) "68/push ")
10909       (print-int32-buffered *(ebp+8) %edx)
10910       (write-buffered *(ebp+8) "/imm32\n")
10911       eb/jump $emit-subx-var-def:end/disp8
10912     }
10913     # while n > 0
10914     {
10915       81 7/subop/compare %edx 0/imm32
10916       7e/jump-if-<= break/disp8
10917       (emit-indent *(ebp+8) *Curr-block-depth)
10918       (write-buffered *(ebp+8) "68/push 0/imm32\n")
10919       # n -= 4
10920       81 5/subop/subtract %edx 4/imm32
10921       #
10922       eb/jump loop/disp8
10923     }
10924 $emit-subx-var-def:end:
10925     # . restore registers
10926     5a/pop-to-edx
10927     59/pop-to-ecx
10928     58/pop-to-eax
10929     # . epilogue
10930     89/<- %esp 5/r32/ebp
10931     5d/pop-to-ebp
10932     c3/return
10933 
10934 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
10935     # . prologue
10936     55/push-ebp
10937     89/<- %ebp 4/r32/esp
10938     # . save registers
10939     50/push-eax
10940     51/push-ecx
10941     # - some special-case primitives that don't actually use the 'primitives' data structure
10942     # var op/ecx: (addr array byte) = lookup(stmt->operation)
10943     8b/-> *(ebp+0xc) 1/r32/ecx
10944     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
10945     89/<- %ecx 0/r32/eax
10946     # array size
10947     {
10948       # if (!string-equal?(stmt->operation, "length")) break
10949       (string-equal? %ecx "length")  # => eax
10950       3d/compare-eax-and 0/imm32
10951       0f 84/jump-if-= break/disp32
10952       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
10953       e9/jump $emit-subx-stmt:end/disp32
10954     }
10955     # index into array
10956     {
10957       # if (!string-equal?(stmt->operation, "index")) break
10958       (string-equal? %ecx "index")  # => eax
10959       3d/compare-eax-and 0/imm32
10960       0f 84/jump-if-= break/disp32
10961       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
10962       e9/jump $emit-subx-stmt:end/disp32
10963     }
10964     # compute-offset for index into array
10965     {
10966       # if (!string-equal?(stmt->operation, "compute-offset")) break
10967       (string-equal? %ecx "compute-offset")  # => eax
10968       3d/compare-eax-and 0/imm32
10969       0f 84/jump-if-= break/disp32
10970       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
10971       e9/jump $emit-subx-stmt:end/disp32
10972     }
10973     # get field from record
10974     {
10975       # if (!string-equal?(stmt->operation, "get")) break
10976       (string-equal? %ecx "get")  # => eax
10977       3d/compare-eax-and 0/imm32
10978       0f 84/jump-if-= break/disp32
10979       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
10980       e9/jump $emit-subx-stmt:end/disp32
10981     }
10982     # - if stmt matches a primitive, emit it
10983     {
10984 $emit-subx-stmt:check-for-primitive:
10985       # var curr/eax: (addr primitive)
10986       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
10987       3d/compare-eax-and 0/imm32
10988       74/jump-if-= break/disp8
10989 $emit-subx-stmt:primitive:
10990       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
10991       e9/jump $emit-subx-stmt:end/disp32
10992     }
10993     # - otherwise emit a call
10994     # TODO: type-checking
10995 $emit-subx-stmt:call:
10996     (emit-call *(ebp+8) *(ebp+0xc))
10997 $emit-subx-stmt:end:
10998     # . restore registers
10999     59/pop-to-ecx
11000     58/pop-to-eax
11001     # . epilogue
11002     89/<- %esp 5/r32/ebp
11003     5d/pop-to-ebp
11004     c3/return
11005 
11006 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11007     # . prologue
11008     55/push-ebp
11009     89/<- %ebp 4/r32/esp
11010     # . save registers
11011     50/push-eax
11012     51/push-ecx
11013     52/push-edx
11014     53/push-ebx
11015     56/push-esi
11016     # esi = stmt
11017     8b/-> *(ebp+0xc) 6/r32/esi
11018     # var base/ebx: (addr var) = stmt->inouts[0]->value
11019     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11020     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11021     89/<- %ebx 0/r32/eax
11022     # var elemsize/ecx: int = array-element-size(base)
11023     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
11024     89/<- %ecx 0/r32/eax
11025     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
11026     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11027     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11028     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11029     89/<- %edx 0/r32/eax
11030     # if elemsize == 1
11031     {
11032       81 7/subop/compare %ecx 1/imm32
11033       75/jump-if-!= break/disp8
11034 $translate-mu-length-stmt:size-1:
11035       (emit-save-size-to *(ebp+8) %ebx %edx)
11036       e9/jump $translate-mu-length-stmt:end/disp32
11037     }
11038     # if elemsize is a power of 2 less than 256
11039     {
11040       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
11041       3d/compare-eax-and 0/imm32/false
11042       74/jump-if-= break/disp8
11043       81 7/subop/compare %ecx 0xff/imm32
11044       7f/jump-if-> break/disp8
11045 $translate-mu-length-stmt:size-power-of-2:
11046       (emit-save-size-to *(ebp+8) %ebx %edx)
11047       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
11048       e9/jump $translate-mu-length-stmt:end/disp32
11049     }
11050     # otherwise, the complex case
11051     # . emit register spills
11052     {
11053 $translate-mu-length-stmt:complex:
11054       (string-equal? %edx "eax")  # => eax
11055       3d/compare-eax-and 0/imm32/false
11056       75/break-if-!= break/disp8
11057       (emit-indent *(ebp+8) *Curr-block-depth)
11058       (write-buffered *(ebp+8) "50/push-eax\n")
11059     }
11060     {
11061       (string-equal? %edx "ecx")  # => eax
11062       3d/compare-eax-and 0/imm32/false
11063       75/break-if-!= break/disp8
11064       (emit-indent *(ebp+8) *Curr-block-depth)
11065       (write-buffered *(ebp+8) "51/push-ecx\n")
11066     }
11067     {
11068       (string-equal? %edx "edx")  # => eax
11069       3d/compare-eax-and 0/imm32/false
11070       75/break-if-!= break/disp8
11071       (emit-indent *(ebp+8) *Curr-block-depth)
11072       (write-buffered *(ebp+8) "52/push-edx\n")
11073     }
11074     # .
11075     (emit-save-size-to *(ebp+8) %ebx "eax")
11076     (emit-indent *(ebp+8) *Curr-block-depth)
11077     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
11078     (emit-indent *(ebp+8) *Curr-block-depth)
11079     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
11080     (print-int32-buffered *(ebp+8) %ecx)
11081     (write-buffered *(ebp+8) "/imm32\n")
11082     (emit-indent *(ebp+8) *Curr-block-depth)
11083     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
11084     {
11085       (string-equal? %edx "eax")  # => eax
11086       3d/compare-eax-and 0/imm32/false
11087       75/break-if-!= break/disp8
11088       (emit-indent *(ebp+8) *Curr-block-depth)
11089       (write-buffered *(ebp+8) "89/<- %")
11090       (write-buffered *(ebp+8) %edx)
11091       (write-buffered *(ebp+8) " 0/r32/eax\n")
11092     }
11093     # . emit register restores
11094     {
11095       (string-equal? %edx "edx")  # => eax
11096       3d/compare-eax-and 0/imm32/false
11097       75/break-if-!= break/disp8
11098       (emit-indent *(ebp+8) *Curr-block-depth)
11099       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
11100     }
11101     {
11102       (string-equal? %edx "ecx")  # => eax
11103       3d/compare-eax-and 0/imm32/false
11104       75/break-if-!= break/disp8
11105       (emit-indent *(ebp+8) *Curr-block-depth)
11106       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
11107     }
11108     {
11109       (string-equal? %edx "eax")  # => eax
11110       3d/compare-eax-and 0/imm32/false
11111       75/break-if-!= break/disp8
11112       (emit-indent *(ebp+8) *Curr-block-depth)
11113       (write-buffered *(ebp+8) "58/pop-to-eax\n")
11114     }
11115 $translate-mu-length-stmt:end:
11116     # . restore registers
11117     5e/pop-to-esi
11118     5b/pop-to-ebx
11119     5a/pop-to-edx
11120     59/pop-to-ecx
11121     58/pop-to-eax
11122     # . epilogue
11123     89/<- %esp 5/r32/ebp
11124     5d/pop-to-ebp
11125     c3/return
11126 
11127 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
11128     # . prologue
11129     55/push-ebp
11130     89/<- %ebp 4/r32/esp
11131     #
11132     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
11133     (size-of-type-id-as-array-element %eax)  # => eax
11134 $array-element-size:end:
11135     # . epilogue
11136     89/<- %esp 5/r32/ebp
11137     5d/pop-to-ebp
11138     c3/return
11139 
11140 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
11141     # . prologue
11142     55/push-ebp
11143     89/<- %ebp 4/r32/esp
11144     # eax = t
11145     8b/-> *(ebp+8) 0/r32/eax
11146     # if t is 'byte', size is 1
11147     3d/compare-eax-and 8/imm32/byte
11148     {
11149       75/jump-if-!= break/disp8
11150       b8/copy-to-eax 1/imm32
11151       eb/jump $array-element-size:end/disp8
11152     }
11153     # otherwise proceed as usual
11154     (size-of-type-id %eax)  # => eax
11155 $size-of-type-id-as-array-element:end:
11156     # . epilogue
11157     89/<- %esp 5/r32/ebp
11158     5d/pop-to-ebp
11159     c3/return
11160 
11161 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
11162     # . prologue
11163     55/push-ebp
11164     89/<- %ebp 4/r32/esp
11165     # . save registers
11166     50/push-eax
11167     53/push-ebx
11168     # ebx = base
11169     8b/-> *(ebp+0xc) 3/r32/ebx
11170     (emit-indent *(ebp+8) *Curr-block-depth)
11171     (write-buffered *(ebp+8) "8b/-> *")
11172     # if base is an (addr array ...) in a register
11173     {
11174       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
11175       74/jump-if-= break/disp8
11176 $emit-save-size-to:emit-base-from-register:
11177       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
11178       (write-buffered *(ebp+8) %eax)
11179       eb/jump $emit-save-size-to:emit-output/disp8
11180     }
11181     # otherwise if base is an (array ...) on the stack
11182     {
11183       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
11184       74/jump-if-= break/disp8
11185 $emit-save-size-to:emit-base-from-stack:
11186       (write-buffered *(ebp+8) "(ebp+")
11187       (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
11188       (write-buffered *(ebp+8) ")")
11189     }
11190 $emit-save-size-to:emit-output:
11191     (write-buffered *(ebp+8) " ")
11192     (get Registers *(ebp+0x10) 0xc "Registers")  # => eax
11193     (print-int32-buffered *(ebp+8) *eax)
11194     (write-buffered *(ebp+8) "/r32\n")
11195 $emit-save-size-to:end:
11196     # . restore registers
11197     5b/pop-to-ebx
11198     58/pop-to-eax
11199     # . epilogue
11200     89/<- %esp 5/r32/ebp
11201     5d/pop-to-ebp
11202     c3/return
11203 
11204 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
11205     # . prologue
11206     55/push-ebp
11207     89/<- %ebp 4/r32/esp
11208     # . save registers
11209     50/push-eax
11210     #
11211     (emit-indent *(ebp+8) *Curr-block-depth)
11212     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
11213     (write-buffered *(ebp+8) *(ebp+0xc))
11214     (write-buffered *(ebp+8) Space)
11215     (num-shift-rights *(ebp+0x10))  # => eax
11216     (print-int32-buffered *(ebp+8) %eax)
11217     (write-buffered *(ebp+8) "/imm8\n")
11218 $emit-divide-by-shift-right:end:
11219     # . restore registers
11220     58/pop-to-eax
11221     # . epilogue
11222     89/<- %esp 5/r32/ebp
11223     5d/pop-to-ebp
11224     c3/return
11225 
11226 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11227     # . prologue
11228     55/push-ebp
11229     89/<- %ebp 4/r32/esp
11230     # . save registers
11231     51/push-ecx
11232     # ecx = stmt
11233     8b/-> *(ebp+0xc) 1/r32/ecx
11234     # var base/ecx: (addr var) = stmt->inouts[0]
11235     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11236     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11237     89/<- %ecx 0/r32/eax
11238     # if (var->register) do one thing
11239     {
11240       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
11241       74/jump-if-= break/disp8
11242       # TODO: ensure there's no dereference
11243       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11244       eb/jump $translate-mu-index-stmt:end/disp8
11245     }
11246     # if (var->offset) do a different thing
11247     {
11248       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
11249       74/jump-if-= break/disp8
11250       # TODO: ensure there's no dereference
11251       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11252       eb/jump $translate-mu-index-stmt:end/disp8
11253     }
11254 $translate-mu-index-stmt:end:
11255     # . restore registers
11256     59/pop-to-ecx
11257     # . epilogue
11258     89/<- %esp 5/r32/ebp
11259     5d/pop-to-ebp
11260     c3/return
11261 
11262 $translate-mu-index-stmt-with-array:error1:
11263     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
11264     (flush *(ebp+0x10))
11265     (stop *(ebp+0x14) 1)
11266     # never gets here
11267 
11268 $translate-mu-index-stmt-with-array:error2:
11269     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
11270     (flush *(ebp+0x10))
11271     (stop *(ebp+0x14) 1)
11272     # never gets here
11273 
11274 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11275     # . prologue
11276     55/push-ebp
11277     89/<- %ebp 4/r32/esp
11278     # . save registers
11279     50/push-eax
11280     51/push-ecx
11281     52/push-edx
11282     53/push-ebx
11283     #
11284     (emit-indent *(ebp+8) *Curr-block-depth)
11285     (write-buffered *(ebp+8) "8d/copy-address *(")
11286     # TODO: ensure inouts[0] is in a register and not dereferenced
11287 $translate-mu-index-stmt-with-array-in-register:emit-base:
11288     # ecx = stmt
11289     8b/-> *(ebp+0xc) 1/r32/ecx
11290     # var base/ebx: (addr var) = inouts[0]
11291     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11292     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11293     89/<- %ebx 0/r32/eax
11294     # print base->register " + "
11295     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
11296     (write-buffered *(ebp+8) %eax)
11297     (write-buffered *(ebp+8) " + ")
11298     # var index/edx: (addr var) = inouts[1]
11299     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11300     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11301     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11302     89/<- %edx 0/r32/eax
11303     # if index->register
11304     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
11305     {
11306       0f 84/jump-if-= break/disp32
11307 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
11308       # if index is an int
11309       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11310       (is-simple-mu-type? %eax 1)  # int => eax
11311       3d/compare-eax-and 0/imm32/false
11312       {
11313         0f 84/jump-if-= break/disp32
11314 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
11315         # print index->register "<<" log2(array-element-size(base)) " + 4) "
11316         # . index->register "<<"
11317         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
11318         (write-buffered *(ebp+8) %eax)
11319         (write-buffered *(ebp+8) "<<")
11320         # . log2(array-element-size(base->type))
11321         # TODO: ensure size is a power of 2
11322         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
11323         (num-shift-rights %eax)  # => eax
11324         (print-int32-buffered *(ebp+8) %eax)
11325         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
11326       }
11327       # if index->type is any other atom, abort
11328       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11329       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11330       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
11331       # if index has type (offset ...)
11332       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11333       (is-simple-mu-type? %eax 7)  # => eax
11334       3d/compare-eax-and 0/imm32/false
11335       {
11336         0f 84/jump-if-= break/disp32
11337         # print index->register
11338 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
11339         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
11340         (write-buffered *(ebp+8) %eax)
11341       }
11342 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
11343       (write-buffered *(ebp+8) " + 4) ")
11344       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
11345     }
11346     # otherwise if index is a literal
11347     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11348     (is-simple-mu-type? %eax 0)  # => eax
11349     3d/compare-eax-and 0/imm32/false
11350     {
11351       0f 84/jump-if-= break/disp32
11352 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
11353       # var index-value/edx: int = parse-hex-int(index->name)
11354       (lookup *edx *(edx+4))  # Var-name Var-name => eax
11355       (parse-hex-int %eax)  # => eax
11356       89/<- %edx 0/r32/eax
11357       # offset = idx-value * array-element-size(base->type)
11358       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
11359       f7 4/subop/multiply-into-eax %edx  # clobbers edx
11360       # offset += 4 for array size
11361       05/add-to-eax 4/imm32
11362       # TODO: check edx for overflow
11363       # print offset
11364       (print-int32-buffered *(ebp+8) %eax)
11365       (write-buffered *(ebp+8) ") ")
11366       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
11367     }
11368     # otherwise abort
11369     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
11370 $translate-mu-index-stmt-with-array-in-register:emit-output:
11371     # outputs[0] "/r32"
11372     8b/-> *(ebp+0xc) 1/r32/ecx
11373     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11374     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11375     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11376     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
11377     (print-int32-buffered *(ebp+8) *eax)
11378     (write-buffered *(ebp+8) "/r32\n")
11379 $translate-mu-index-stmt-with-array-in-register:end:
11380     # . restore registers
11381     5b/pop-to-ebx
11382     5a/pop-to-edx
11383     59/pop-to-ecx
11384     58/pop-to-eax
11385     # . epilogue
11386     89/<- %esp 5/r32/ebp
11387     5d/pop-to-ebp
11388     c3/return
11389 
11390 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11391     # . prologue
11392     55/push-ebp
11393     89/<- %ebp 4/r32/esp
11394     # . save registers
11395     50/push-eax
11396     51/push-ecx
11397     52/push-edx
11398     53/push-ebx
11399     #
11400     (emit-indent *(ebp+8) *Curr-block-depth)
11401     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
11402     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
11403     8b/-> *(ebp+0xc) 0/r32/eax
11404     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11405     89/<- %edx 0/r32/eax
11406     # var base/ecx: (addr var) = lookup(curr->value)
11407     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11408     89/<- %ecx 0/r32/eax
11409     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
11410     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
11411     # var index/edx: (handle var) = curr2->value
11412     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11413     89/<- %edx 0/r32/eax
11414     # if index->register
11415     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
11416     {
11417       0f 84/jump-if-= break/disp32
11418 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
11419       # if index is an int
11420       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11421       (is-simple-mu-type? %eax 1)  # int => eax
11422       3d/compare-eax-and 0/imm32/false
11423       {
11424         0f 84/jump-if-= break/disp32
11425 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
11426         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
11427         # . inouts[1]->register "<<"
11428         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
11429         (write-buffered *(ebp+8) %eax)
11430         (write-buffered *(ebp+8) "<<")
11431         # . log2(array-element-size(base))
11432         # TODO: ensure size is a power of 2
11433         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
11434         (num-shift-rights %eax)  # => eax
11435         (print-int32-buffered *(ebp+8) %eax)
11436         #
11437         (write-buffered *(ebp+8) " + ")
11438         #
11439         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
11440         05/add-to-eax 4/imm32  # for array length
11441         (print-int32-buffered *(ebp+8) %eax)
11442         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
11443       }
11444       # if index->type is any other atom, abort
11445       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11446       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11447       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
11448       # if index has type (offset ...)
11449       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11450       (is-simple-mu-type? %eax 7)  # => eax
11451       3d/compare-eax-and 0/imm32/false
11452       {
11453         0f 84/jump-if-= break/disp32
11454         # print index->register
11455 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
11456         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
11457         (write-buffered *(ebp+8) %eax)
11458       }
11459 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
11460       (write-buffered *(ebp+8) ") ")
11461       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
11462     }
11463     # otherwise if index is a literal
11464     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
11465     (is-simple-mu-type? %eax 0)  # => eax
11466     3d/compare-eax-and 0/imm32/false
11467     {
11468       0f 84/jump-if-= break/disp32
11469 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
11470       # var idx-value/edx: int = parse-hex-int(index->name)
11471       (lookup *edx *(edx+4))  # Var-name Var-name => eax
11472       (parse-hex-int %eax)  # Var-name => eax
11473       89/<- %edx 0/r32/eax
11474       # offset = idx-value * array-element-size(base)
11475       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
11476       f7 4/subop/multiply-into-eax %edx  # clobbers edx
11477       # offset += base->offset
11478       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
11479       # offset += 4 for array size
11480       05/add-to-eax 4/imm32
11481       # TODO: check edx for overflow
11482       # print offset
11483       (print-int32-buffered *(ebp+8) %eax)
11484       (write-buffered *(ebp+8) ") ")
11485       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
11486     }
11487     # otherwise abort
11488     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
11489 $translate-mu-index-stmt-with-array-on-stack:emit-output:
11490     # outputs[0] "/r32"
11491     8b/-> *(ebp+0xc) 0/r32/eax
11492     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11493     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11494     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11495     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
11496     (print-int32-buffered *(ebp+8) *eax)
11497     (write-buffered *(ebp+8) "/r32\n")
11498 $translate-mu-index-stmt-with-array-on-stack:end:
11499     # . restore registers
11500     5b/pop-to-ebx
11501     5a/pop-to-edx
11502     59/pop-to-ecx
11503     58/pop-to-eax
11504     # . epilogue
11505     89/<- %esp 5/r32/ebp
11506     5d/pop-to-ebp
11507     c3/return
11508 
11509 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
11510     # . prologue
11511     55/push-ebp
11512     89/<- %ebp 4/r32/esp
11513     # . save registers
11514     50/push-eax
11515     51/push-ecx
11516     52/push-edx
11517     53/push-ebx
11518     #
11519     (emit-indent *(ebp+8) *Curr-block-depth)
11520     (write-buffered *(ebp+8) "69/multiply")
11521     # ecx = stmt
11522     8b/-> *(ebp+0xc) 1/r32/ecx
11523     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
11524     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11525     89/<- %ebx 0/r32/eax
11526 $translate-mu-compute-index-stmt:emit-index:
11527     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
11528     (emit-subx-var-as-rm32 *(ebp+8) %eax)
11529     (write-buffered *(ebp+8) Space)
11530 $translate-mu-compute-index-stmt:emit-elem-size:
11531     # var base/ebx: (addr var)
11532     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
11533     89/<- %ebx 0/r32/eax
11534     # print array-element-size(base)
11535     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
11536     (print-int32-buffered *(ebp+8) %eax)
11537     (write-buffered *(ebp+8) "/imm32 ")
11538 $translate-mu-compute-index-stmt:emit-output:
11539     # outputs[0] "/r32"
11540     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11541     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11542     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11543     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
11544     (print-int32-buffered *(ebp+8) *eax)
11545     (write-buffered *(ebp+8) "/r32\n")
11546 $translate-mu-compute-index-stmt:end:
11547     # . restore registers
11548     5b/pop-to-ebx
11549     5a/pop-to-edx
11550     59/pop-to-ecx
11551     58/pop-to-eax
11552     # . epilogue
11553     89/<- %esp 5/r32/ebp
11554     5d/pop-to-ebp
11555     c3/return
11556 
11557 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
11558     # . prologue
11559     55/push-ebp
11560     89/<- %ebp 4/r32/esp
11561     # . save registers
11562     50/push-eax
11563     51/push-ecx
11564     52/push-edx
11565     #
11566     (emit-indent *(ebp+8) *Curr-block-depth)
11567     (write-buffered *(ebp+8) "8d/copy-address ")
11568     # ecx = stmt
11569     8b/-> *(ebp+0xc) 1/r32/ecx
11570     # var offset/edx: int = get offset of stmt
11571     (mu-get-offset %ecx)  # => eax
11572     89/<- %edx 0/r32/eax
11573     # var base/eax: (addr var) = stmt->inouts->value
11574     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11575     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11576     # if base is in a register
11577     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
11578     {
11579       0f 84/jump-if-= break/disp32
11580 $translate-mu-get-stmt:emit-register-input:
11581       # emit "*(" base->register " + " offset ") "
11582       (write-buffered *(ebp+8) "*(")
11583       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11584       (write-buffered *(ebp+8) %eax)
11585       (write-buffered *(ebp+8) " + ")
11586       (print-int32-buffered *(ebp+8) %edx)
11587       (write-buffered *(ebp+8) ") ")
11588       e9/jump $translate-mu-get-stmt:emit-output/disp32
11589     }
11590     # otherwise base is on the stack
11591     {
11592 $translate-mu-get-stmt:emit-stack-input:
11593       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
11594       (write-buffered *(ebp+8) "*(ebp+")
11595       03/add *(eax+0x14) 2/r32/edx  # Var-offset
11596       (print-int32-buffered *(ebp+8) %edx)
11597       (write-buffered *(ebp+8) ") ")
11598       eb/jump $translate-mu-get-stmt:emit-output/disp8
11599     }
11600 $translate-mu-get-stmt:emit-output:
11601     # var output/eax: (addr var) = stmt->outputs->value
11602     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11603     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11604     # emit offset->register "/r32"
11605     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
11606     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
11607     (print-int32-buffered *(ebp+8) *eax)
11608     (write-buffered *(ebp+8) "/r32\n")
11609 $translate-mu-get-stmt:end:
11610     # . restore registers
11611     5a/pop-to-edx
11612     59/pop-to-ecx
11613     58/pop-to-eax
11614     # . epilogue
11615     89/<- %esp 5/r32/ebp
11616     5d/pop-to-ebp
11617     c3/return
11618 
11619 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
11620     # precondition: n is positive
11621     # . prologue
11622     55/push-ebp
11623     89/<- %ebp 4/r32/esp
11624     #
11625     8b/-> *(ebp+8) 0/r32/eax
11626     # var t/eax: (addr tree type-id)
11627     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11628     # if t == 0 abort
11629     3d/compare-eax-with 0/imm32
11630     0f 84/jump-if-== $array-element-type-id:error0/disp32
11631     # if t->is-atom? abort
11632     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11633     0f 85/jump-if-!= $array-element-type-id:error1/disp32
11634     # if (t->left == addr) t = t->right
11635     {
11636       50/push-eax
11637       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11638       (is-simple-mu-type? %eax 2)  # addr => eax
11639       3d/compare-eax-with 0/imm32/false
11640       58/pop-to-eax
11641       74/jump-if-= break/disp8
11642 $array-element-type-id:skip-addr:
11643       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
11644     }
11645     # if t == 0 abort
11646     3d/compare-eax-with 0/imm32
11647     0f 84/jump-if-= $array-element-type-id:error2/disp32
11648     # if t->is-atom? abort
11649     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11650     0f 85/jump-if-!= $array-element-type-id:error2/disp32
11651     # if t->left != array abort
11652     {
11653       50/push-eax
11654       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11655       (is-simple-mu-type? %eax 3)  # array => eax
11656       3d/compare-eax-with 0/imm32/false
11657       58/pop-to-eax
11658 $array-element-type-id:no-array:
11659       0f 84/jump-if-= $array-element-type-id:error2/disp32
11660     }
11661 $array-element-type-id:skip-array:
11662     # t = t->right
11663     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
11664     # if t == 0 abort
11665     3d/compare-eax-with 0/imm32
11666     0f 84/jump-if-= $array-element-type-id:error2/disp32
11667     # if t->is-atom? abort
11668     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
11669     0f 85/jump-if-!= $array-element-type-id:error2/disp32
11670     # return t->left->value
11671     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
11672     8b/-> *(eax+4) 0/r32/eax  # Tree-value
11673 $array-element-type-id:end:
11674     # . epilogue
11675     89/<- %esp 5/r32/ebp
11676     5d/pop-to-ebp
11677     c3/return
11678 
11679 $array-element-type-id:error0:
11680     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
11681     50/push-eax
11682     8b/-> *(ebp+8) 0/r32/eax
11683     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11684     (write-buffered *(ebp+0xc) %eax)
11685     58/pop-to-eax
11686     (write-buffered *(ebp+0xc) "' has no type\n")
11687     (flush *(ebp+0xc))
11688     (stop *(ebp+0x10) 1)
11689     # never gets here
11690 
11691 $array-element-type-id:error1:
11692     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
11693     50/push-eax
11694     8b/-> *(ebp+8) 0/r32/eax
11695     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11696     (write-buffered *(ebp+0xc) %eax)
11697     58/pop-to-eax
11698     (write-buffered *(ebp+0xc) "' has atomic type ")
11699     (print-int32-buffered *(ebp+0xc) *(eax+4))  # Tree-value
11700     (write-buffered *(ebp+0xc) Newline)
11701     (flush *(ebp+0xc))
11702     (stop *(ebp+0x10) 1)
11703     # never gets here
11704 
11705 $array-element-type-id:error2:
11706     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
11707     50/push-eax
11708     8b/-> *(ebp+8) 0/r32/eax
11709     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11710     (write-buffered *(ebp+0xc) %eax)
11711     58/pop-to-eax
11712     (write-buffered *(ebp+0xc) "' has non-array type\n")
11713     (flush *(ebp+0xc))
11714     (stop *(ebp+0x10) 1)
11715     # never gets here
11716 
11717 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
11718     # precondition: n is positive
11719     # . prologue
11720     55/push-ebp
11721     89/<- %ebp 4/r32/esp
11722     # eax = n
11723     8b/-> *(ebp+8) 0/r32/eax
11724     # if (n < 0) abort
11725     3d/compare-eax-with 0/imm32
11726     0f 8c/jump-if-< $power-of-2?:abort/disp32
11727     # var tmp/eax: int = n-1
11728     48/decrement-eax
11729     # var tmp2/eax: int = n & tmp
11730     23/and-> *(ebp+8) 0/r32/eax
11731     # return (tmp2 == 0)
11732     3d/compare-eax-and 0/imm32
11733     0f 94/set-byte-if-= %al
11734     81 4/subop/and %eax 0xff/imm32
11735 $power-of-2?:end:
11736     # . epilogue
11737     89/<- %esp 5/r32/ebp
11738     5d/pop-to-ebp
11739     c3/return
11740 
11741 $power-of-2?:abort:
11742     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
11743     (flush *(ebp+0xc))
11744     (stop *(ebp+0x10) 1)
11745     # never gets here
11746 
11747 num-shift-rights:  # n: int -> result/eax: int
11748     # precondition: n is a positive power of 2
11749     # . prologue
11750     55/push-ebp
11751     89/<- %ebp 4/r32/esp
11752     # . save registers
11753     51/push-ecx
11754     # var curr/ecx: int = n
11755     8b/-> *(ebp+8) 1/r32/ecx
11756     # result = 0
11757     b8/copy-to-eax 0/imm32
11758     {
11759       # if (curr <= 1) break
11760       81 7/subop/compare %ecx 1/imm32
11761       7e/jump-if-<= break/disp8
11762       40/increment-eax
11763       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
11764       eb/jump loop/disp8
11765     }
11766 $num-shift-rights:end:
11767     # . restore registers
11768     59/pop-to-ecx
11769     # . epilogue
11770     89/<- %esp 5/r32/ebp
11771     5d/pop-to-ebp
11772     c3/return
11773 
11774 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
11775     # . prologue
11776     55/push-ebp
11777     89/<- %ebp 4/r32/esp
11778     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
11779     8b/-> *(ebp+8) 0/r32/eax
11780     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11781     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11782     # var output-var/eax: (addr var) = second-inout->value
11783     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11784 #?     (write-buffered Stderr "mu-get-offset: ")
11785 #?     (print-int32-buffered Stderr %eax)
11786 #?     (write-buffered Stderr " name: ")
11787 #?     50/push-eax
11788 #?     (lookup *eax *(eax+4))  # Var-name
11789 #?     (write-buffered Stderr %eax)
11790 #?     58/pop-to-eax
11791 #?     (write-buffered Stderr Newline)
11792 #?     (flush Stderr)
11793     # return output-var->stack-offset
11794     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
11795 #?     (write-buffered Stderr "=> ")
11796 #?     (print-int32-buffered Stderr %eax)
11797 #?     (write-buffered Stderr Newline)
11798 #?     (flush Stderr)
11799 $emit-get-offset:end:
11800     # . epilogue
11801     89/<- %esp 5/r32/ebp
11802     5d/pop-to-ebp
11803     c3/return
11804 
11805 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
11806     # . prologue
11807     55/push-ebp
11808     89/<- %ebp 4/r32/esp
11809     # . save registers
11810     50/push-eax
11811     51/push-ecx
11812     56/push-esi
11813     # esi = block
11814     8b/-> *(ebp+0xc) 6/r32/esi
11815     # block->var->block-depth = *Curr-block-depth
11816     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
11817     8b/-> *Curr-block-depth 1/r32/ecx
11818     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
11819     # var stmts/eax: (addr list stmt) = lookup(block->statements)
11820     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
11821     #
11822     {
11823 $emit-subx-block:check-empty:
11824       3d/compare-eax-and 0/imm32
11825       0f 84/jump-if-= break/disp32
11826       (emit-indent *(ebp+8) *Curr-block-depth)
11827       (write-buffered *(ebp+8) "{\n")
11828       # var v/ecx: (addr var) = lookup(block->var)
11829       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
11830       89/<- %ecx 0/r32/eax
11831       #
11832       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11833       (write-buffered *(ebp+8) %eax)
11834       (write-buffered *(ebp+8) ":loop:\n")
11835       ff 0/subop/increment *Curr-block-depth
11836       (push *(ebp+0x10) *(esi+0xc))  # Block-var
11837       (push *(ebp+0x10) *(esi+0x10))  # Block-var
11838       (push *(ebp+0x10) 0)  # false
11839       # emit block->statements
11840       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
11841       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
11842       (pop *(ebp+0x10))  # => eax
11843       (pop *(ebp+0x10))  # => eax
11844       (pop *(ebp+0x10))  # => eax
11845       ff 1/subop/decrement *Curr-block-depth
11846       (emit-indent *(ebp+8) *Curr-block-depth)
11847       (write-buffered *(ebp+8) "}\n")
11848       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11849       (write-buffered *(ebp+8) %eax)
11850       (write-buffered *(ebp+8) ":break:\n")
11851     }
11852 $emit-subx-block:end:
11853     # . restore registers
11854     5e/pop-to-esi
11855     59/pop-to-ecx
11856     58/pop-to-eax
11857     # . epilogue
11858     89/<- %esp 5/r32/ebp
11859     5d/pop-to-ebp
11860     c3/return
11861 
11862 # Primitives supported
11863 # See mu_instructions for a summary of this linked-list data structure.
11864 #
11865 # For each operation, put variants with hard-coded registers before flexible ones.
11866 #
11867 # Unfortunately, our restrictions on addresses require that various fields in
11868 # primitives be handles, which complicates these definitions.
11869 #   - we need to insert dummy fields all over the place for fake alloc-ids
11870 #   - we can't use our syntax sugar of quoted literals for string fields
11871 #
11872 # Fake alloc-ids are needed because our type definitions up top require
11873 # handles but it's clearer to statically allocate these long-lived objects.
11874 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
11875 #
11876 # Every 'object' below starts with a fake alloc-id. It may also contain other
11877 # fake alloc-ids for various handle fields.
11878 #
11879 # I think of objects starting with a fake alloc-id as having type 'payload'.
11880 # It's not really intended to be created dynamically; for that use `allocate`
11881 # as usual.
11882 #
11883 # Idea for a notation to simplify such definitions:
11884 #   _Primitive-increment-eax:  # (payload primitive)
11885 #     0x11/alloc-id:fake:payload
11886 #     0x11 @(0x11 "increment")  # name
11887 #     0 0                       # inouts
11888 #     0x11 @(0x11/payload
11889 #            0x11 @(0x11/payload  # List-value
11890 #                   0 0             # Var-name
11891 #                   0x11 @(0x11     # Var-type
11892 #                          1/is-atom
11893 #                          1/value 0/unused   # Tree-left
11894 #                          0 0                # Tree-right
11895 #                         )
11896 #                   1               # block-depth
11897 #                   0               # stack-offset
11898 #                   0x11 @(0x11 "eax")  # Var-register
11899 #                  )
11900 #            0 0)                 # List-next
11901 #     ...
11902 #     _Primitive-increment-ecx/imm32/next
11903 #   ...
11904 # Awfully complex and non-obvious. But also clearly signals there's something
11905 # to learn here, so may be worth trying.
11906 #
11907 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
11908 #
11909 # For now we'll continue to just use comments and manually ensure they stay up
11910 # to date.
11911 == data
11912 Primitives:  # (addr primitive)
11913 # - increment/decrement
11914 _Primitive-increment-eax:  # (addr primitive)
11915     # var/eax <- increment => 40/increment-eax
11916     0x11/imm32/alloc-id:fake
11917     _string-increment/imm32/name
11918     0/imm32/no-inouts
11919     0/imm32/no-inouts
11920     0x11/imm32/alloc-id:fake
11921     Single-int-var-in-eax/imm32/outputs
11922     0x11/imm32/alloc-id:fake
11923     _string_40_increment_eax/imm32/subx-name
11924     0/imm32/no-rm32
11925     0/imm32/no-r32
11926     0/imm32/no-imm32
11927     0/imm32/no-disp32
11928     0/imm32/output-is-write-only
11929     0x11/imm32/alloc-id:fake
11930     _Primitive-increment-ecx/imm32/next
11931 _Primitive-increment-ecx:  # (payload primitive)
11932     0x11/imm32/alloc-id:fake:payload
11933     # var/ecx <- increment => 41/increment-ecx
11934     0x11/imm32/alloc-id:fake
11935     _string-increment/imm32/name
11936     0/imm32/no-inouts
11937     0/imm32/no-inouts
11938     0x11/imm32/alloc-id:fake
11939     Single-int-var-in-ecx/imm32/outputs
11940     0x11/imm32/alloc-id:fake
11941     _string_41_increment_ecx/imm32/subx-name
11942     0/imm32/no-rm32
11943     0/imm32/no-r32
11944     0/imm32/no-imm32
11945     0/imm32/no-disp32
11946     0/imm32/output-is-write-only
11947     0x11/imm32/alloc-id:fake
11948     _Primitive-increment-edx/imm32/next
11949 _Primitive-increment-edx:  # (payload primitive)
11950     0x11/imm32/alloc-id:fake:payload
11951     # var/edx <- increment => 42/increment-edx
11952     0x11/imm32/alloc-id:fake
11953     _string-increment/imm32/name
11954     0/imm32/no-inouts
11955     0/imm32/no-inouts
11956     0x11/imm32/alloc-id:fake
11957     Single-int-var-in-edx/imm32/outputs
11958     0x11/imm32/alloc-id:fake
11959     _string_42_increment_edx/imm32/subx-name
11960     0/imm32/no-rm32
11961     0/imm32/no-r32
11962     0/imm32/no-imm32
11963     0/imm32/no-disp32
11964     0/imm32/output-is-write-only
11965     0x11/imm32/alloc-id:fake
11966     _Primitive-increment-ebx/imm32/next
11967 _Primitive-increment-ebx:  # (payload primitive)
11968     0x11/imm32/alloc-id:fake:payload
11969     # var/ebx <- increment => 43/increment-ebx
11970     0x11/imm32/alloc-id:fake
11971     _string-increment/imm32/name
11972     0/imm32/no-inouts
11973     0/imm32/no-inouts
11974     0x11/imm32/alloc-id:fake
11975     Single-int-var-in-ebx/imm32/outputs
11976     0x11/imm32/alloc-id:fake
11977     _string_43_increment_ebx/imm32/subx-name
11978     0/imm32/no-rm32
11979     0/imm32/no-r32
11980     0/imm32/no-imm32
11981     0/imm32/no-disp32
11982     0/imm32/output-is-write-only
11983     0x11/imm32/alloc-id:fake
11984     _Primitive-increment-esi/imm32/next
11985 _Primitive-increment-esi:  # (payload primitive)
11986     0x11/imm32/alloc-id:fake:payload
11987     # var/esi <- increment => 46/increment-esi
11988     0x11/imm32/alloc-id:fake
11989     _string-increment/imm32/name
11990     0/imm32/no-inouts
11991     0/imm32/no-inouts
11992     0x11/imm32/alloc-id:fake
11993     Single-int-var-in-esi/imm32/outputs
11994     0x11/imm32/alloc-id:fake
11995     _string_46_increment_esi/imm32/subx-name
11996     0/imm32/no-rm32
11997     0/imm32/no-r32
11998     0/imm32/no-imm32
11999     0/imm32/no-disp32
12000     0/imm32/output-is-write-only
12001     0x11/imm32/alloc-id:fake
12002     _Primitive-increment-edi/imm32/next
12003 _Primitive-increment-edi:  # (payload primitive)
12004     0x11/imm32/alloc-id:fake:payload
12005     # var/edi <- increment => 47/increment-edi
12006     0x11/imm32/alloc-id:fake
12007     _string-increment/imm32/name
12008     0/imm32/no-inouts
12009     0/imm32/no-inouts
12010     0x11/imm32/alloc-id:fake
12011     Single-int-var-in-edi/imm32/outputs
12012     0x11/imm32/alloc-id:fake
12013     _string_47_increment_edi/imm32/subx-name
12014     0/imm32/no-rm32
12015     0/imm32/no-r32
12016     0/imm32/no-imm32
12017     0/imm32/no-disp32
12018     0/imm32/output-is-write-only
12019     0x11/imm32/alloc-id:fake
12020     _Primitive-decrement-eax/imm32/next
12021 _Primitive-decrement-eax:  # (payload primitive)
12022     0x11/imm32/alloc-id:fake:payload
12023     # var/eax <- decrement => 48/decrement-eax
12024     0x11/imm32/alloc-id:fake
12025     _string-decrement/imm32/name
12026     0/imm32/no-inouts
12027     0/imm32/no-inouts
12028     0x11/imm32/alloc-id:fake
12029     Single-int-var-in-eax/imm32/outputs
12030     0x11/imm32/alloc-id:fake
12031     _string_48_decrement_eax/imm32/subx-name
12032     0/imm32/no-rm32
12033     0/imm32/no-r32
12034     0/imm32/no-imm32
12035     0/imm32/no-disp32
12036     0/imm32/output-is-write-only
12037     0x11/imm32/alloc-id:fake
12038     _Primitive-decrement-ecx/imm32/next
12039 _Primitive-decrement-ecx:  # (payload primitive)
12040     0x11/imm32/alloc-id:fake:payload
12041     # var/ecx <- decrement => 49/decrement-ecx
12042     0x11/imm32/alloc-id:fake
12043     _string-decrement/imm32/name
12044     0/imm32/no-inouts
12045     0/imm32/no-inouts
12046     0x11/imm32/alloc-id:fake
12047     Single-int-var-in-ecx/imm32/outputs
12048     0x11/imm32/alloc-id:fake
12049     _string_49_decrement_ecx/imm32/subx-name
12050     0/imm32/no-rm32
12051     0/imm32/no-r32
12052     0/imm32/no-imm32
12053     0/imm32/no-disp32
12054     0/imm32/output-is-write-only
12055     0x11/imm32/alloc-id:fake
12056     _Primitive-decrement-edx/imm32/next
12057 _Primitive-decrement-edx:  # (payload primitive)
12058     0x11/imm32/alloc-id:fake:payload
12059     # var/edx <- decrement => 4a/decrement-edx
12060     0x11/imm32/alloc-id:fake
12061     _string-decrement/imm32/name
12062     0/imm32/no-inouts
12063     0/imm32/no-inouts
12064     0x11/imm32/alloc-id:fake
12065     Single-int-var-in-edx/imm32/outputs
12066     0x11/imm32/alloc-id:fake
12067     _string_4a_decrement_edx/imm32/subx-name
12068     0/imm32/no-rm32
12069     0/imm32/no-r32
12070     0/imm32/no-imm32
12071     0/imm32/no-disp32
12072     0/imm32/output-is-write-only
12073     0x11/imm32/alloc-id:fake
12074     _Primitive-decrement-ebx/imm32/next
12075 _Primitive-decrement-ebx:  # (payload primitive)
12076     0x11/imm32/alloc-id:fake:payload
12077     # var/ebx <- decrement => 4b/decrement-ebx
12078     0x11/imm32/alloc-id:fake
12079     _string-decrement/imm32/name
12080     0/imm32/no-inouts
12081     0/imm32/no-inouts
12082     0x11/imm32/alloc-id:fake
12083     Single-int-var-in-ebx/imm32/outputs
12084     0x11/imm32/alloc-id:fake
12085     _string_4b_decrement_ebx/imm32/subx-name
12086     0/imm32/no-rm32
12087     0/imm32/no-r32
12088     0/imm32/no-imm32
12089     0/imm32/no-disp32
12090     0/imm32/output-is-write-only
12091     0x11/imm32/alloc-id:fake
12092     _Primitive-decrement-esi/imm32/next
12093 _Primitive-decrement-esi:  # (payload primitive)
12094     0x11/imm32/alloc-id:fake:payload
12095     # var/esi <- decrement => 4e/decrement-esi
12096     0x11/imm32/alloc-id:fake
12097     _string-decrement/imm32/name
12098     0/imm32/no-inouts
12099     0/imm32/no-inouts
12100     0x11/imm32/alloc-id:fake
12101     Single-int-var-in-esi/imm32/outputs
12102     0x11/imm32/alloc-id:fake
12103     _string_4e_decrement_esi/imm32/subx-name
12104     0/imm32/no-rm32
12105     0/imm32/no-r32
12106     0/imm32/no-imm32
12107     0/imm32/no-disp32
12108     0/imm32/output-is-write-only
12109     0x11/imm32/alloc-id:fake
12110     _Primitive-decrement-edi/imm32/next
12111 _Primitive-decrement-edi:  # (payload primitive)
12112     0x11/imm32/alloc-id:fake:payload
12113     # var/edi <- decrement => 4f/decrement-edi
12114     0x11/imm32/alloc-id:fake
12115     _string-decrement/imm32/name
12116     0/imm32/no-inouts
12117     0/imm32/no-inouts
12118     0x11/imm32/alloc-id:fake
12119     Single-int-var-in-edi/imm32/outputs
12120     0x11/imm32/alloc-id:fake
12121     _string_4f_decrement_edi/imm32/subx-name
12122     0/imm32/no-rm32
12123     0/imm32/no-r32
12124     0/imm32/no-imm32
12125     0/imm32/no-disp32
12126     0/imm32/output-is-write-only
12127     0x11/imm32/alloc-id:fake
12128     _Primitive-increment-mem/imm32/next
12129 _Primitive-increment-mem:  # (payload primitive)
12130     0x11/imm32/alloc-id:fake:payload
12131     # increment var => ff 0/subop/increment *(ebp+__)
12132     0x11/imm32/alloc-id:fake
12133     _string-increment/imm32/name
12134     0x11/imm32/alloc-id:fake
12135     Single-int-var-in-mem/imm32/inouts
12136     0/imm32/no-outputs
12137     0/imm32/no-outputs
12138     0x11/imm32/alloc-id:fake
12139     _string_ff_subop_increment/imm32/subx-name
12140     1/imm32/rm32-is-first-inout
12141     0/imm32/no-r32
12142     0/imm32/no-imm32
12143     0/imm32/no-disp32
12144     0/imm32/output-is-write-only
12145     0x11/imm32/alloc-id:fake
12146     _Primitive-increment-reg/imm32/next
12147 _Primitive-increment-reg:  # (payload primitive)
12148     0x11/imm32/alloc-id:fake:payload
12149     # var/reg <- increment => ff 0/subop/increment %__
12150     0x11/imm32/alloc-id:fake
12151     _string-increment/imm32/name
12152     0/imm32/no-inouts
12153     0/imm32/no-inouts
12154     0x11/imm32/alloc-id:fake
12155     Single-int-var-in-some-register/imm32/outputs
12156     0x11/imm32/alloc-id:fake
12157     _string_ff_subop_increment/imm32/subx-name
12158     3/imm32/rm32-is-first-output
12159     0/imm32/no-r32
12160     0/imm32/no-imm32
12161     0/imm32/no-disp32
12162     0/imm32/output-is-write-only
12163     0x11/imm32/alloc-id:fake
12164     _Primitive-decrement-mem/imm32/next
12165 _Primitive-decrement-mem:  # (payload primitive)
12166     0x11/imm32/alloc-id:fake:payload
12167     # decrement var => ff 1/subop/decrement *(ebp+__)
12168     0x11/imm32/alloc-id:fake
12169     _string-decrement/imm32/name
12170     0x11/imm32/alloc-id:fake
12171     Single-int-var-in-mem/imm32/inouts
12172     0/imm32/no-outputs
12173     0/imm32/no-outputs
12174     0x11/imm32/alloc-id:fake
12175     _string_ff_subop_decrement/imm32/subx-name
12176     1/imm32/rm32-is-first-inout
12177     0/imm32/no-r32
12178     0/imm32/no-imm32
12179     0/imm32/no-disp32
12180     0/imm32/output-is-write-only
12181     0x11/imm32/alloc-id:fake
12182     _Primitive-decrement-reg/imm32/next
12183 _Primitive-decrement-reg:  # (payload primitive)
12184     0x11/imm32/alloc-id:fake:payload
12185     # var/reg <- decrement => ff 1/subop/decrement %__
12186     0x11/imm32/alloc-id:fake
12187     _string-decrement/imm32/name
12188     0/imm32/no-inouts
12189     0/imm32/no-inouts
12190     0x11/imm32/alloc-id:fake
12191     Single-int-var-in-some-register/imm32/outputs
12192     0x11/imm32/alloc-id:fake
12193     _string_ff_subop_decrement/imm32/subx-name
12194     3/imm32/rm32-is-first-output
12195     0/imm32/no-r32
12196     0/imm32/no-imm32
12197     0/imm32/no-disp32
12198     0/imm32/output-is-write-only
12199     0x11/imm32/alloc-id:fake
12200     _Primitive-add-to-eax/imm32/next
12201 # - add
12202 _Primitive-add-to-eax:  # (payload primitive)
12203     0x11/imm32/alloc-id:fake:payload
12204     # var/eax <- add lit => 05/add-to-eax lit/imm32
12205     0x11/imm32/alloc-id:fake
12206     _string-add/imm32/name
12207     0x11/imm32/alloc-id:fake
12208     Single-lit-var/imm32/inouts
12209     0x11/imm32/alloc-id:fake
12210     Single-int-var-in-eax/imm32/outputs
12211     0x11/imm32/alloc-id:fake
12212     _string_05_add_to_eax/imm32/subx-name
12213     0/imm32/no-rm32
12214     0/imm32/no-r32
12215     1/imm32/imm32-is-first-inout
12216     0/imm32/no-disp32
12217     0/imm32/output-is-write-only
12218     0x11/imm32/alloc-id:fake
12219     _Primitive-add-reg-to-reg/imm32/next
12220 _Primitive-add-reg-to-reg:  # (payload primitive)
12221     0x11/imm32/alloc-id:fake:payload
12222     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
12223     0x11/imm32/alloc-id:fake
12224     _string-add/imm32/name
12225     0x11/imm32/alloc-id:fake
12226     Single-int-var-in-some-register/imm32/inouts
12227     0x11/imm32/alloc-id:fake
12228     Single-int-var-in-some-register/imm32/outputs
12229     0x11/imm32/alloc-id:fake
12230     _string_01_add_to/imm32/subx-name
12231     3/imm32/rm32-is-first-output
12232     1/imm32/r32-is-first-inout
12233     0/imm32/no-imm32
12234     0/imm32/no-disp32
12235     0/imm32/output-is-write-only
12236     0x11/imm32/alloc-id:fake
12237     _Primitive-add-reg-to-mem/imm32/next
12238 _Primitive-add-reg-to-mem:  # (payload primitive)
12239     0x11/imm32/alloc-id:fake:payload
12240     # add-to var1 var2/reg => 01/add-to var1 var2/r32
12241     0x11/imm32/alloc-id:fake
12242     _string-add-to/imm32/name
12243     0x11/imm32/alloc-id:fake
12244     Two-args-int-stack-int-reg/imm32/inouts
12245     0/imm32/no-outputs
12246     0/imm32/no-outputs
12247     0x11/imm32/alloc-id:fake
12248     _string_01_add_to/imm32/subx-name
12249     1/imm32/rm32-is-first-inout
12250     2/imm32/r32-is-second-inout
12251     0/imm32/no-imm32
12252     0/imm32/no-disp32
12253     0/imm32/output-is-write-only
12254     0x11/imm32/alloc-id:fake
12255     _Primitive-add-mem-to-reg/imm32/next
12256 _Primitive-add-mem-to-reg:  # (payload primitive)
12257     0x11/imm32/alloc-id:fake:payload
12258     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
12259     0x11/imm32/alloc-id:fake
12260     _string-add/imm32/name
12261     0x11/imm32/alloc-id:fake
12262     Single-int-var-in-mem/imm32/inouts
12263     0x11/imm32/alloc-id:fake
12264     Single-int-var-in-some-register/imm32/outputs
12265     0x11/imm32/alloc-id:fake
12266     _string_03_add/imm32/subx-name
12267     1/imm32/rm32-is-first-inout
12268     3/imm32/r32-is-first-output
12269     0/imm32/no-imm32
12270     0/imm32/no-disp32
12271     0/imm32/output-is-write-only
12272     0x11/imm32/alloc-id:fake
12273     _Primitive-add-lit-to-reg/imm32/next
12274 _Primitive-add-lit-to-reg:  # (payload primitive)
12275     0x11/imm32/alloc-id:fake:payload
12276     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
12277     0x11/imm32/alloc-id:fake
12278     _string-add/imm32/name
12279     0x11/imm32/alloc-id:fake
12280     Single-lit-var/imm32/inouts
12281     0x11/imm32/alloc-id:fake
12282     Single-int-var-in-some-register/imm32/outputs
12283     0x11/imm32/alloc-id:fake
12284     _string_81_subop_add/imm32/subx-name
12285     3/imm32/rm32-is-first-output
12286     0/imm32/no-r32
12287     1/imm32/imm32-is-first-inout
12288     0/imm32/no-disp32
12289     0/imm32/output-is-write-only
12290     0x11/imm32/alloc-id:fake
12291     _Primitive-add-lit-to-mem/imm32/next
12292 _Primitive-add-lit-to-mem:  # (payload primitive)
12293     0x11/imm32/alloc-id:fake:payload
12294     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
12295     0x11/imm32/alloc-id:fake
12296     _string-add-to/imm32/name
12297     0x11/imm32/alloc-id:fake
12298     Int-var-and-literal/imm32/inouts
12299     0/imm32/no-outputs
12300     0/imm32/no-outputs
12301     0x11/imm32/alloc-id:fake
12302     _string_81_subop_add/imm32/subx-name
12303     1/imm32/rm32-is-first-inout
12304     0/imm32/no-r32
12305     2/imm32/imm32-is-second-inout
12306     0/imm32/no-disp32
12307     0/imm32/output-is-write-only
12308     0x11/imm32/alloc-id:fake
12309     _Primitive-subtract-from-eax/imm32/next
12310 # - subtract
12311 _Primitive-subtract-from-eax:  # (payload primitive)
12312     0x11/imm32/alloc-id:fake:payload
12313     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
12314     0x11/imm32/alloc-id:fake
12315     _string-subtract/imm32/name
12316     0x11/imm32/alloc-id:fake
12317     Single-lit-var/imm32/inouts
12318     0x11/imm32/alloc-id:fake
12319     Single-int-var-in-eax/imm32/outputs
12320     0x11/imm32/alloc-id:fake
12321     _string_2d_subtract_from_eax/imm32/subx-name
12322     0/imm32/no-rm32
12323     0/imm32/no-r32
12324     1/imm32/imm32-is-first-inout
12325     0/imm32/no-disp32
12326     0/imm32/output-is-write-only
12327     0x11/imm32/alloc-id:fake
12328     _Primitive-subtract-reg-from-reg/imm32/next
12329 _Primitive-subtract-reg-from-reg:  # (payload primitive)
12330     0x11/imm32/alloc-id:fake:payload
12331     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
12332     0x11/imm32/alloc-id:fake
12333     _string-subtract/imm32/name
12334     0x11/imm32/alloc-id:fake
12335     Single-int-var-in-some-register/imm32/inouts
12336     0x11/imm32/alloc-id:fake
12337     Single-int-var-in-some-register/imm32/outputs
12338     0x11/imm32/alloc-id:fake
12339     _string_29_subtract_from/imm32/subx-name
12340     3/imm32/rm32-is-first-output
12341     1/imm32/r32-is-first-inout
12342     0/imm32/no-imm32
12343     0/imm32/no-disp32
12344     0/imm32/output-is-write-only
12345     0x11/imm32/alloc-id:fake
12346     _Primitive-subtract-reg-from-mem/imm32/next
12347 _Primitive-subtract-reg-from-mem:  # (payload primitive)
12348     0x11/imm32/alloc-id:fake:payload
12349     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
12350     0x11/imm32/alloc-id:fake
12351     _string-subtract-from/imm32/name
12352     0x11/imm32/alloc-id:fake
12353     Two-args-int-stack-int-reg/imm32/inouts
12354     0/imm32/no-outputs
12355     0/imm32/no-outputs
12356     0x11/imm32/alloc-id:fake
12357     _string_29_subtract_from/imm32/subx-name
12358     1/imm32/rm32-is-first-inout
12359     2/imm32/r32-is-second-inout
12360     0/imm32/no-imm32
12361     0/imm32/no-disp32
12362     0/imm32/output-is-write-only
12363     0x11/imm32/alloc-id:fake
12364     _Primitive-subtract-mem-from-reg/imm32/next
12365 _Primitive-subtract-mem-from-reg:  # (payload primitive)
12366     0x11/imm32/alloc-id:fake:payload
12367     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
12368     0x11/imm32/alloc-id:fake
12369     _string-subtract/imm32/name
12370     0x11/imm32/alloc-id:fake
12371     Single-int-var-in-mem/imm32/inouts
12372     0x11/imm32/alloc-id:fake
12373     Single-int-var-in-some-register/imm32/outputs
12374     0x11/imm32/alloc-id:fake
12375     _string_2b_subtract/imm32/subx-name
12376     1/imm32/rm32-is-first-inout
12377     3/imm32/r32-is-first-output
12378     0/imm32/no-imm32
12379     0/imm32/no-disp32
12380     0/imm32/output-is-write-only
12381     0x11/imm32/alloc-id:fake
12382     _Primitive-subtract-lit-from-reg/imm32/next
12383 _Primitive-subtract-lit-from-reg:  # (payload primitive)
12384     0x11/imm32/alloc-id:fake:payload
12385     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
12386     0x11/imm32/alloc-id:fake
12387     _string-subtract/imm32/name
12388     0x11/imm32/alloc-id:fake
12389     Single-lit-var/imm32/inouts
12390     0x11/imm32/alloc-id:fake
12391     Single-int-var-in-some-register/imm32/outputs
12392     0x11/imm32/alloc-id:fake
12393     _string_81_subop_subtract/imm32/subx-name
12394     3/imm32/rm32-is-first-output
12395     0/imm32/no-r32
12396     1/imm32/imm32-is-first-inout
12397     0/imm32/no-disp32
12398     0/imm32/output-is-write-only
12399     0x11/imm32/alloc-id:fake
12400     _Primitive-subtract-lit-from-mem/imm32/next
12401 _Primitive-subtract-lit-from-mem:  # (payload primitive)
12402     0x11/imm32/alloc-id:fake:payload
12403     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
12404     0x11/imm32/alloc-id:fake
12405     _string-subtract-from/imm32/name
12406     0x11/imm32/alloc-id:fake
12407     Int-var-and-literal/imm32/inouts
12408     0/imm32/no-outputs
12409     0/imm32/no-outputs
12410     0x11/imm32/alloc-id:fake
12411     _string_81_subop_subtract/imm32/subx-name
12412     1/imm32/rm32-is-first-inout
12413     0/imm32/no-r32
12414     2/imm32/imm32-is-first-inout
12415     0/imm32/no-disp32
12416     0/imm32/output-is-write-only
12417     0x11/imm32/alloc-id:fake
12418     _Primitive-and-with-eax/imm32/next
12419 # - and
12420 _Primitive-and-with-eax:  # (payload primitive)
12421     0x11/imm32/alloc-id:fake:payload
12422     # var/eax <- and lit => 25/and-with-eax lit/imm32
12423     0x11/imm32/alloc-id:fake
12424     _string-and/imm32/name
12425     0x11/imm32/alloc-id:fake
12426     Single-lit-var/imm32/inouts
12427     0x11/imm32/alloc-id:fake
12428     Single-int-var-in-eax/imm32/outputs
12429     0x11/imm32/alloc-id:fake
12430     _string_25_and_with_eax/imm32/subx-name
12431     0/imm32/no-rm32
12432     0/imm32/no-r32
12433     1/imm32/imm32-is-first-inout
12434     0/imm32/no-disp32
12435     0/imm32/output-is-write-only
12436     0x11/imm32/alloc-id:fake
12437     _Primitive-and-reg-with-reg/imm32/next
12438 _Primitive-and-reg-with-reg:  # (payload primitive)
12439     0x11/imm32/alloc-id:fake:payload
12440     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
12441     0x11/imm32/alloc-id:fake
12442     _string-and/imm32/name
12443     0x11/imm32/alloc-id:fake
12444     Single-int-var-in-some-register/imm32/inouts
12445     0x11/imm32/alloc-id:fake
12446     Single-int-var-in-some-register/imm32/outputs
12447     0x11/imm32/alloc-id:fake
12448     _string_21_and_with/imm32/subx-name
12449     3/imm32/rm32-is-first-output
12450     1/imm32/r32-is-first-inout
12451     0/imm32/no-imm32
12452     0/imm32/no-disp32
12453     0/imm32/output-is-write-only
12454     0x11/imm32/alloc-id:fake
12455     _Primitive-and-reg-with-mem/imm32/next
12456 _Primitive-and-reg-with-mem:  # (payload primitive)
12457     0x11/imm32/alloc-id:fake:payload
12458     # and-with var1 var2/reg => 21/and-with var1 var2/r32
12459     0x11/imm32/alloc-id:fake
12460     _string-and-with/imm32/name
12461     0x11/imm32/alloc-id:fake
12462     Two-args-int-stack-int-reg/imm32/inouts
12463     0/imm32/no-outputs
12464     0/imm32/no-outputs
12465     0x11/imm32/alloc-id:fake
12466     _string_21_and_with/imm32/subx-name
12467     1/imm32/rm32-is-first-inout
12468     2/imm32/r32-is-second-inout
12469     0/imm32/no-imm32
12470     0/imm32/no-disp32
12471     0/imm32/output-is-write-only
12472     0x11/imm32/alloc-id:fake
12473     _Primitive-and-mem-with-reg/imm32/next
12474 _Primitive-and-mem-with-reg:  # (payload primitive)
12475     0x11/imm32/alloc-id:fake:payload
12476     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
12477     0x11/imm32/alloc-id:fake
12478     _string-and/imm32/name
12479     0x11/imm32/alloc-id:fake
12480     Single-int-var-in-mem/imm32/inouts
12481     0x11/imm32/alloc-id:fake
12482     Single-int-var-in-some-register/imm32/outputs
12483     0x11/imm32/alloc-id:fake
12484     _string_23_and/imm32/subx-name
12485     1/imm32/rm32-is-first-inout
12486     3/imm32/r32-is-first-output
12487     0/imm32/no-imm32
12488     0/imm32/no-disp32
12489     0/imm32/output-is-write-only
12490     0x11/imm32/alloc-id:fake
12491     _Primitive-and-lit-with-reg/imm32/next
12492 _Primitive-and-lit-with-reg:  # (payload primitive)
12493     0x11/imm32/alloc-id:fake:payload
12494     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
12495     0x11/imm32/alloc-id:fake
12496     _string-and/imm32/name
12497     0x11/imm32/alloc-id:fake
12498     Single-lit-var/imm32/inouts
12499     0x11/imm32/alloc-id:fake
12500     Single-int-var-in-some-register/imm32/outputs
12501     0x11/imm32/alloc-id:fake
12502     _string_81_subop_and/imm32/subx-name
12503     3/imm32/rm32-is-first-output
12504     0/imm32/no-r32
12505     1/imm32/imm32-is-first-inout
12506     0/imm32/no-disp32
12507     0/imm32/output-is-write-only
12508     0x11/imm32/alloc-id:fake
12509     _Primitive-and-lit-with-mem/imm32/next
12510 _Primitive-and-lit-with-mem:  # (payload primitive)
12511     0x11/imm32/alloc-id:fake:payload
12512     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
12513     0x11/imm32/alloc-id:fake
12514     _string-and-with/imm32/name
12515     0x11/imm32/alloc-id:fake
12516     Int-var-and-literal/imm32/inouts
12517     0/imm32/no-outputs
12518     0/imm32/no-outputs
12519     0x11/imm32/alloc-id:fake
12520     _string_81_subop_and/imm32/subx-name
12521     1/imm32/rm32-is-first-inout
12522     0/imm32/no-r32
12523     2/imm32/imm32-is-first-inout
12524     0/imm32/no-disp32
12525     0/imm32/output-is-write-only
12526     0x11/imm32/alloc-id:fake
12527     _Primitive-or-with-eax/imm32/next
12528 # - or
12529 _Primitive-or-with-eax:  # (payload primitive)
12530     0x11/imm32/alloc-id:fake:payload
12531     # var/eax <- or lit => 0d/or-with-eax lit/imm32
12532     0x11/imm32/alloc-id:fake
12533     _string-or/imm32/name
12534     0x11/imm32/alloc-id:fake
12535     Single-lit-var/imm32/inouts
12536     0x11/imm32/alloc-id:fake
12537     Single-int-var-in-eax/imm32/outputs
12538     0x11/imm32/alloc-id:fake
12539     _string_0d_or_with_eax/imm32/subx-name
12540     0/imm32/no-rm32
12541     0/imm32/no-r32
12542     1/imm32/imm32-is-first-inout
12543     0/imm32/no-disp32
12544     0/imm32/output-is-write-only
12545     0x11/imm32/alloc-id:fake
12546     _Primitive-or-reg-with-reg/imm32/next
12547 _Primitive-or-reg-with-reg:  # (payload primitive)
12548     0x11/imm32/alloc-id:fake:payload
12549     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
12550     0x11/imm32/alloc-id:fake
12551     _string-or/imm32/name
12552     0x11/imm32/alloc-id:fake
12553     Single-int-var-in-some-register/imm32/inouts
12554     0x11/imm32/alloc-id:fake
12555     Single-int-var-in-some-register/imm32/outputs
12556     0x11/imm32/alloc-id:fake
12557     _string_09_or_with/imm32/subx-name
12558     3/imm32/rm32-is-first-output
12559     1/imm32/r32-is-first-inout
12560     0/imm32/no-imm32
12561     0/imm32/no-disp32
12562     0/imm32/output-is-write-only
12563     0x11/imm32/alloc-id:fake
12564     _Primitive-or-reg-with-mem/imm32/next
12565 _Primitive-or-reg-with-mem:  # (payload primitive)
12566     0x11/imm32/alloc-id:fake:payload
12567     # or-with var1 var2/reg => 09/or-with var1 var2/r32
12568     0x11/imm32/alloc-id:fake
12569     _string-or-with/imm32/name
12570     0x11/imm32/alloc-id:fake
12571     Two-args-int-stack-int-reg/imm32/inouts
12572     0/imm32/no-outputs
12573     0/imm32/no-outputs
12574     0x11/imm32/alloc-id:fake
12575     _string_09_or_with/imm32/subx-name
12576     1/imm32/rm32-is-first-inout
12577     2/imm32/r32-is-second-inout
12578     0/imm32/no-imm32
12579     0/imm32/no-disp32
12580     0/imm32/output-is-write-only
12581     0x11/imm32/alloc-id:fake
12582     _Primitive-or-mem-with-reg/imm32/next
12583 _Primitive-or-mem-with-reg:  # (payload primitive)
12584     0x11/imm32/alloc-id:fake:payload
12585     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
12586     0x11/imm32/alloc-id:fake
12587     _string-or/imm32/name
12588     0x11/imm32/alloc-id:fake
12589     Single-int-var-in-mem/imm32/inouts
12590     0x11/imm32/alloc-id:fake
12591     Single-int-var-in-some-register/imm32/outputs
12592     0x11/imm32/alloc-id:fake
12593     _string_0b_or/imm32/subx-name
12594     1/imm32/rm32-is-first-inout
12595     3/imm32/r32-is-first-output
12596     0/imm32/no-imm32
12597     0/imm32/no-disp32
12598     0/imm32/output-is-write-only
12599     0x11/imm32/alloc-id:fake
12600     _Primitive-or-lit-with-reg/imm32/next
12601 _Primitive-or-lit-with-reg:  # (payload primitive)
12602     0x11/imm32/alloc-id:fake:payload
12603     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
12604     0x11/imm32/alloc-id:fake
12605     _string-or/imm32/name
12606     0x11/imm32/alloc-id:fake
12607     Single-lit-var/imm32/inouts
12608     0x11/imm32/alloc-id:fake
12609     Single-int-var-in-some-register/imm32/outputs
12610     0x11/imm32/alloc-id:fake
12611     _string_81_subop_or/imm32/subx-name
12612     3/imm32/rm32-is-first-output
12613     0/imm32/no-r32
12614     1/imm32/imm32-is-first-inout
12615     0/imm32/no-disp32
12616     0/imm32/output-is-write-only
12617     0x11/imm32/alloc-id:fake
12618     _Primitive-or-lit-with-mem/imm32/next
12619 _Primitive-or-lit-with-mem:  # (payload primitive)
12620     0x11/imm32/alloc-id:fake:payload
12621     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
12622     0x11/imm32/alloc-id:fake
12623     _string-or-with/imm32/name
12624     0x11/imm32/alloc-id:fake
12625     Int-var-and-literal/imm32/inouts
12626     0/imm32/no-outputs
12627     0/imm32/no-outputs
12628     0x11/imm32/alloc-id:fake
12629     _string_81_subop_or/imm32/subx-name
12630     1/imm32/rm32-is-first-inout
12631     0/imm32/no-r32
12632     2/imm32/imm32-is-second-inout
12633     0/imm32/no-disp32
12634     0/imm32/output-is-write-only
12635     0x11/imm32/alloc-id:fake
12636     _Primitive-xor-with-eax/imm32/next
12637 # - xor
12638 _Primitive-xor-with-eax:  # (payload primitive)
12639     0x11/imm32/alloc-id:fake:payload
12640     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
12641     0x11/imm32/alloc-id:fake
12642     _string-xor/imm32/name
12643     0x11/imm32/alloc-id:fake
12644     Single-lit-var/imm32/inouts
12645     0x11/imm32/alloc-id:fake
12646     Single-int-var-in-eax/imm32/outputs
12647     0x11/imm32/alloc-id:fake
12648     _string_35_xor_with_eax/imm32/subx-name
12649     0/imm32/no-rm32
12650     0/imm32/no-r32
12651     1/imm32/imm32-is-first-inout
12652     0/imm32/no-disp32
12653     0/imm32/output-is-write-only
12654     0x11/imm32/alloc-id:fake
12655     _Primitive-xor-reg-with-reg/imm32/next
12656 _Primitive-xor-reg-with-reg:  # (payload primitive)
12657     0x11/imm32/alloc-id:fake:payload
12658     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
12659     0x11/imm32/alloc-id:fake
12660     _string-xor/imm32/name
12661     0x11/imm32/alloc-id:fake
12662     Single-int-var-in-some-register/imm32/inouts
12663     0x11/imm32/alloc-id:fake
12664     Single-int-var-in-some-register/imm32/outputs
12665     0x11/imm32/alloc-id:fake
12666     _string_31_xor_with/imm32/subx-name
12667     3/imm32/rm32-is-first-output
12668     1/imm32/r32-is-first-inout
12669     0/imm32/no-imm32
12670     0/imm32/no-disp32
12671     0/imm32/output-is-write-only
12672     0x11/imm32/alloc-id:fake
12673     _Primitive-xor-reg-with-mem/imm32/next
12674 _Primitive-xor-reg-with-mem:  # (payload primitive)
12675     0x11/imm32/alloc-id:fake:payload
12676     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
12677     0x11/imm32/alloc-id:fake
12678     _string-xor-with/imm32/name
12679     0x11/imm32/alloc-id:fake
12680     Two-args-int-stack-int-reg/imm32/inouts
12681     0/imm32/no-outputs
12682     0/imm32/no-outputs
12683     0x11/imm32/alloc-id:fake
12684     _string_31_xor_with/imm32/subx-name
12685     1/imm32/rm32-is-first-inout
12686     2/imm32/r32-is-second-inout
12687     0/imm32/no-imm32
12688     0/imm32/no-disp32
12689     0/imm32/output-is-write-only
12690     0x11/imm32/alloc-id:fake
12691     _Primitive-xor-mem-with-reg/imm32/next
12692 _Primitive-xor-mem-with-reg:  # (payload primitive)
12693     0x11/imm32/alloc-id:fake:payload
12694     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
12695     0x11/imm32/alloc-id:fake
12696     _string-xor/imm32/name
12697     0x11/imm32/alloc-id:fake
12698     Single-int-var-in-mem/imm32/inouts
12699     0x11/imm32/alloc-id:fake
12700     Single-int-var-in-some-register/imm32/outputs
12701     0x11/imm32/alloc-id:fake
12702     _string_33_xor/imm32/subx-name
12703     1/imm32/rm32-is-first-inout
12704     3/imm32/r32-is-first-output
12705     0/imm32/no-imm32
12706     0/imm32/no-disp32
12707     0/imm32/output-is-write-only
12708     0x11/imm32/alloc-id:fake
12709     _Primitive-xor-lit-with-reg/imm32/next
12710 _Primitive-xor-lit-with-reg:  # (payload primitive)
12711     0x11/imm32/alloc-id:fake:payload
12712     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
12713     0x11/imm32/alloc-id:fake
12714     _string-xor/imm32/name
12715     0x11/imm32/alloc-id:fake
12716     Single-lit-var/imm32/inouts
12717     0x11/imm32/alloc-id:fake
12718     Single-int-var-in-some-register/imm32/outputs
12719     0x11/imm32/alloc-id:fake
12720     _string_81_subop_xor/imm32/subx-name
12721     3/imm32/rm32-is-first-output
12722     0/imm32/no-r32
12723     1/imm32/imm32-is-first-inout
12724     0/imm32/no-disp32
12725     0/imm32/output-is-write-only
12726     0x11/imm32/alloc-id:fake
12727     _Primitive-xor-lit-with-mem/imm32/next
12728 _Primitive-xor-lit-with-mem:  # (payload primitive)
12729     0x11/imm32/alloc-id:fake:payload
12730     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
12731     0x11/imm32/alloc-id:fake
12732     _string-xor-with/imm32/name
12733     0x11/imm32/alloc-id:fake
12734     Int-var-and-literal/imm32/inouts
12735     0/imm32/no-outputs
12736     0/imm32/no-outputs
12737     0x11/imm32/alloc-id:fake
12738     _string_81_subop_xor/imm32/subx-name
12739     1/imm32/rm32-is-first-inout
12740     0/imm32/no-r32
12741     2/imm32/imm32-is-first-inout
12742     0/imm32/no-disp32
12743     0/imm32/output-is-write-only
12744     0x11/imm32/alloc-id:fake
12745     _Primitive-copy-to-eax/imm32/next
12746 # - copy
12747 _Primitive-copy-to-eax:  # (payload primitive)
12748     0x11/imm32/alloc-id:fake:payload
12749     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
12750     0x11/imm32/alloc-id:fake
12751     _string-copy/imm32/name
12752     0x11/imm32/alloc-id:fake
12753     Single-lit-var/imm32/inouts
12754     0x11/imm32/alloc-id:fake
12755     Single-int-var-in-eax/imm32/outputs
12756     0x11/imm32/alloc-id:fake
12757     _string_b8_copy_to_eax/imm32/subx-name
12758     0/imm32/no-rm32
12759     0/imm32/no-r32
12760     1/imm32/imm32-is-first-inout
12761     0/imm32/no-disp32
12762     1/imm32/output-is-write-only
12763     0x11/imm32/alloc-id:fake
12764     _Primitive-copy-to-ecx/imm32/next
12765 _Primitive-copy-to-ecx:  # (payload primitive)
12766     0x11/imm32/alloc-id:fake:payload
12767     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
12768     0x11/imm32/alloc-id:fake
12769     _string-copy/imm32/name
12770     0x11/imm32/alloc-id:fake
12771     Single-lit-var/imm32/inouts
12772     0x11/imm32/alloc-id:fake
12773     Single-int-var-in-ecx/imm32/outputs
12774     0x11/imm32/alloc-id:fake
12775     _string_b9_copy_to_ecx/imm32/subx-name
12776     0/imm32/no-rm32
12777     0/imm32/no-r32
12778     1/imm32/imm32-is-first-inout
12779     0/imm32/no-disp32
12780     1/imm32/output-is-write-only
12781     0x11/imm32/alloc-id:fake
12782     _Primitive-copy-to-edx/imm32/next
12783 _Primitive-copy-to-edx:  # (payload primitive)
12784     0x11/imm32/alloc-id:fake:payload
12785     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
12786     0x11/imm32/alloc-id:fake
12787     _string-copy/imm32/name
12788     0x11/imm32/alloc-id:fake
12789     Single-lit-var/imm32/inouts
12790     0x11/imm32/alloc-id:fake
12791     Single-int-var-in-edx/imm32/outputs
12792     0x11/imm32/alloc-id:fake
12793     _string_ba_copy_to_edx/imm32/subx-name
12794     0/imm32/no-rm32
12795     0/imm32/no-r32
12796     1/imm32/imm32-is-first-inout
12797     0/imm32/no-disp32
12798     1/imm32/output-is-write-only
12799     0x11/imm32/alloc-id:fake
12800     _Primitive-copy-to-ebx/imm32/next
12801 _Primitive-copy-to-ebx:  # (payload primitive)
12802     0x11/imm32/alloc-id:fake:payload
12803     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
12804     0x11/imm32/alloc-id:fake
12805     _string-copy/imm32/name
12806     0x11/imm32/alloc-id:fake
12807     Single-lit-var/imm32/inouts
12808     0x11/imm32/alloc-id:fake
12809     Single-int-var-in-ebx/imm32/outputs
12810     0x11/imm32/alloc-id:fake
12811     _string_bb_copy_to_ebx/imm32/subx-name
12812     0/imm32/no-rm32
12813     0/imm32/no-r32
12814     1/imm32/imm32-is-first-inout
12815     0/imm32/no-disp32
12816     1/imm32/output-is-write-only
12817     0x11/imm32/alloc-id:fake
12818     _Primitive-copy-to-esi/imm32/next
12819 _Primitive-copy-to-esi:  # (payload primitive)
12820     0x11/imm32/alloc-id:fake:payload
12821     # var/esi <- copy lit => be/copy-to-esi lit/imm32
12822     0x11/imm32/alloc-id:fake
12823     _string-copy/imm32/name
12824     0x11/imm32/alloc-id:fake
12825     Single-lit-var/imm32/inouts
12826     0x11/imm32/alloc-id:fake
12827     Single-int-var-in-esi/imm32/outputs
12828     0x11/imm32/alloc-id:fake
12829     _string_be_copy_to_esi/imm32/subx-name
12830     0/imm32/no-rm32
12831     0/imm32/no-r32
12832     1/imm32/imm32-is-first-inout
12833     0/imm32/no-disp32
12834     1/imm32/output-is-write-only
12835     0x11/imm32/alloc-id:fake
12836     _Primitive-copy-to-edi/imm32/next
12837 _Primitive-copy-to-edi:  # (payload primitive)
12838     0x11/imm32/alloc-id:fake:payload
12839     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
12840     0x11/imm32/alloc-id:fake
12841     _string-copy/imm32/name
12842     0x11/imm32/alloc-id:fake
12843     Single-lit-var/imm32/inouts
12844     0x11/imm32/alloc-id:fake
12845     Single-int-var-in-edi/imm32/outputs
12846     0x11/imm32/alloc-id:fake
12847     _string_bf_copy_to_edi/imm32/subx-name
12848     0/imm32/no-rm32
12849     0/imm32/no-r32
12850     1/imm32/imm32-is-first-inout
12851     0/imm32/no-disp32
12852     1/imm32/output-is-write-only
12853     0x11/imm32/alloc-id:fake
12854     _Primitive-copy-reg-to-reg/imm32/next
12855 _Primitive-copy-reg-to-reg:  # (payload primitive)
12856     0x11/imm32/alloc-id:fake:payload
12857     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
12858     0x11/imm32/alloc-id:fake
12859     _string-copy/imm32/name
12860     0x11/imm32/alloc-id:fake
12861     Single-int-var-in-some-register/imm32/inouts
12862     0x11/imm32/alloc-id:fake
12863     Single-int-var-in-some-register/imm32/outputs
12864     0x11/imm32/alloc-id:fake
12865     _string_89_<-/imm32/subx-name
12866     3/imm32/rm32-is-first-output
12867     1/imm32/r32-is-first-inout
12868     0/imm32/no-imm32
12869     0/imm32/no-disp32
12870     1/imm32/output-is-write-only
12871     0x11/imm32/alloc-id:fake
12872     _Primitive-copy-reg-to-mem/imm32/next
12873 _Primitive-copy-reg-to-mem:  # (payload primitive)
12874     0x11/imm32/alloc-id:fake:payload
12875     # copy-to var1 var2/reg => 89/<- var1 var2/r32
12876     0x11/imm32/alloc-id:fake
12877     _string-copy-to/imm32/name
12878     0x11/imm32/alloc-id:fake
12879     Two-args-int-stack-int-reg/imm32/inouts
12880     0/imm32/no-outputs
12881     0/imm32/no-outputs
12882     0x11/imm32/alloc-id:fake
12883     _string_89_<-/imm32/subx-name
12884     1/imm32/rm32-is-first-inout
12885     2/imm32/r32-is-second-inout
12886     0/imm32/no-imm32
12887     0/imm32/no-disp32
12888     1/imm32/output-is-write-only
12889     0x11/imm32/alloc-id:fake
12890     _Primitive-copy-mem-to-reg/imm32/next
12891 _Primitive-copy-mem-to-reg:  # (payload primitive)
12892     0x11/imm32/alloc-id:fake:payload
12893     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
12894     0x11/imm32/alloc-id:fake
12895     _string-copy/imm32/name
12896     0x11/imm32/alloc-id:fake
12897     Single-int-var-in-mem/imm32/inouts
12898     0x11/imm32/alloc-id:fake
12899     Single-int-var-in-some-register/imm32/outputs
12900     0x11/imm32/alloc-id:fake
12901     _string_8b_->/imm32/subx-name
12902     1/imm32/rm32-is-first-inout
12903     3/imm32/r32-is-first-output
12904     0/imm32/no-imm32
12905     0/imm32/no-disp32
12906     1/imm32/output-is-write-only
12907     0x11/imm32/alloc-id:fake
12908     _Primitive-copy-lit-to-reg/imm32/next
12909 _Primitive-copy-lit-to-reg:  # (payload primitive)
12910     0x11/imm32/alloc-id:fake:payload
12911     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
12912     0x11/imm32/alloc-id:fake
12913     _string-copy/imm32/name
12914     0x11/imm32/alloc-id:fake
12915     Single-lit-var/imm32/inouts
12916     0x11/imm32/alloc-id:fake
12917     Single-int-var-in-some-register/imm32/outputs
12918     0x11/imm32/alloc-id:fake
12919     _string_c7_subop_copy/imm32/subx-name
12920     3/imm32/rm32-is-first-output
12921     0/imm32/no-r32
12922     1/imm32/imm32-is-first-inout
12923     0/imm32/no-disp32
12924     1/imm32/output-is-write-only
12925     0x11/imm32/alloc-id:fake
12926     _Primitive-copy-lit-to-mem/imm32/next
12927 _Primitive-copy-lit-to-mem:  # (payload primitive)
12928     0x11/imm32/alloc-id:fake:payload
12929     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
12930     0x11/imm32/alloc-id:fake
12931     _string-copy-to/imm32/name
12932     0x11/imm32/alloc-id:fake
12933     Int-var-and-literal/imm32/inouts
12934     0/imm32/no-outputs
12935     0/imm32/no-outputs
12936     0x11/imm32/alloc-id:fake
12937     _string_c7_subop_copy/imm32/subx-name
12938     1/imm32/rm32-is-first-inout
12939     0/imm32/no-r32
12940     2/imm32/imm32-is-first-inout
12941     0/imm32/no-disp32
12942     1/imm32/output-is-write-only
12943     0x11/imm32/alloc-id:fake
12944     _Primitive-copy-byte-from-reg/imm32/next
12945 # - copy byte
12946 _Primitive-copy-byte-from-reg:
12947     0x11/imm32/alloc-id:fake:payload
12948     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
12949     0x11/imm32/alloc-id:fake
12950     _string-copy-byte/imm32/name
12951     0x11/imm32/alloc-id:fake
12952     Single-byte-var-in-some-register/imm32/inouts
12953     0x11/imm32/alloc-id:fake
12954     Single-byte-var-in-some-register/imm32/outputs
12955     0x11/imm32/alloc-id:fake
12956     _string_8a_copy_byte/imm32/subx-name
12957     1/imm32/rm32-is-first-inout
12958     3/imm32/r32-is-first-output
12959     0/imm32/no-imm32
12960     0/imm32/no-disp32
12961     1/imm32/output-is-write-only
12962     0x11/imm32/alloc-id:fake
12963     _Primitive-copy-byte-from-mem/imm32/next
12964 _Primitive-copy-byte-from-mem:
12965     0x11/imm32/alloc-id:fake:payload
12966     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
12967     0x11/imm32/alloc-id:fake
12968     _string-copy-byte/imm32/name
12969     0x11/imm32/alloc-id:fake
12970     Single-byte-var-in-mem/imm32/inouts
12971     0x11/imm32/alloc-id:fake
12972     Single-byte-var-in-some-register/imm32/outputs
12973     0x11/imm32/alloc-id:fake
12974     _string_8a_copy_byte/imm32/subx-name
12975     1/imm32/rm32-is-first-inout
12976     3/imm32/r32-is-first-output
12977     0/imm32/no-imm32
12978     0/imm32/no-disp32
12979     1/imm32/output-is-write-only
12980     0x11/imm32/alloc-id:fake
12981     _Primitive-copy-byte-to-mem/imm32/next
12982 _Primitive-copy-byte-to-mem:
12983     0x11/imm32/alloc-id:fake:payload
12984     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
12985     0x11/imm32/alloc-id:fake
12986     _string-copy-byte-to/imm32/name
12987     0x11/imm32/alloc-id:fake
12988     Two-args-byte-stack-byte-reg/imm32/inouts
12989     0/imm32/no-outputs
12990     0/imm32/no-outputs
12991     0x11/imm32/alloc-id:fake
12992     _string_88_copy_byte/imm32/subx-name
12993     1/imm32/rm32-is-first-inout
12994     2/imm32/r32-is-second-inout
12995     0/imm32/no-imm32
12996     0/imm32/no-disp32
12997     0/imm32/output-is-write-only
12998     0x11/imm32/alloc-id:fake
12999     _Primitive-address/imm32/next
13000 # - address
13001 _Primitive-address:  # (payload primitive)
13002     0x11/imm32/alloc-id:fake:payload
13003     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
13004     0x11/imm32/alloc-id:fake
13005     _string-address/imm32/name
13006     0x11/imm32/alloc-id:fake
13007     Single-int-var-in-mem/imm32/inouts
13008     0x11/imm32/alloc-id:fake
13009     Single-addr-var-in-some-register/imm32/outputs
13010     0x11/imm32/alloc-id:fake
13011     _string_8d_copy_address/imm32/subx-name
13012     1/imm32/rm32-is-first-inout
13013     3/imm32/r32-is-first-output
13014     0/imm32/no-imm32
13015     0/imm32/no-disp32
13016     1/imm32/output-is-write-only
13017     0x11/imm32/alloc-id:fake
13018     _Primitive-compare-reg-with-reg/imm32/next
13019 # - compare
13020 _Primitive-compare-reg-with-reg:  # (payload primitive)
13021     0x11/imm32/alloc-id:fake:payload
13022     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
13023     0x11/imm32/alloc-id:fake
13024     _string-compare/imm32/name
13025     0x11/imm32/alloc-id:fake
13026     Two-int-args-in-regs/imm32/inouts
13027     0/imm32/no-outputs
13028     0/imm32/no-outputs
13029     0x11/imm32/alloc-id:fake
13030     _string_39_compare->/imm32/subx-name
13031     1/imm32/rm32-is-first-inout
13032     2/imm32/r32-is-second-inout
13033     0/imm32/no-imm32
13034     0/imm32/no-disp32
13035     0/imm32/output-is-write-only
13036     0x11/imm32/alloc-id:fake
13037     _Primitive-compare-mem-with-reg/imm32/next
13038 _Primitive-compare-mem-with-reg:  # (payload primitive)
13039     0x11/imm32/alloc-id:fake:payload
13040     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
13041     0x11/imm32/alloc-id:fake
13042     _string-compare/imm32/name
13043     0x11/imm32/alloc-id:fake
13044     Two-args-int-stack-int-reg/imm32/inouts
13045     0/imm32/no-outputs
13046     0/imm32/no-outputs
13047     0x11/imm32/alloc-id:fake
13048     _string_39_compare->/imm32/subx-name
13049     1/imm32/rm32-is-first-inout
13050     2/imm32/r32-is-second-inout
13051     0/imm32/no-imm32
13052     0/imm32/no-disp32
13053     0/imm32/output-is-write-only
13054     0x11/imm32/alloc-id:fake
13055     _Primitive-compare-reg-with-mem/imm32/next
13056 _Primitive-compare-reg-with-mem:  # (payload primitive)
13057     0x11/imm32/alloc-id:fake:payload
13058     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
13059     0x11/imm32/alloc-id:fake
13060     _string-compare/imm32/name
13061     0x11/imm32/alloc-id:fake
13062     Two-args-int-reg-int-stack/imm32/inouts
13063     0/imm32/no-outputs
13064     0/imm32/no-outputs
13065     0x11/imm32/alloc-id:fake
13066     _string_3b_compare<-/imm32/subx-name
13067     2/imm32/rm32-is-second-inout
13068     1/imm32/r32-is-first-inout
13069     0/imm32/no-imm32
13070     0/imm32/no-disp32
13071     0/imm32/output-is-write-only
13072     0x11/imm32/alloc-id:fake
13073     _Primitive-compare-eax-with-literal/imm32/next
13074 _Primitive-compare-eax-with-literal:  # (payload primitive)
13075     0x11/imm32/alloc-id:fake:payload
13076     # compare var1/eax n => 3d/compare-eax-with n/imm32
13077     0x11/imm32/alloc-id:fake
13078     _string-compare/imm32/name
13079     0x11/imm32/alloc-id:fake
13080     Two-args-int-eax-int-literal/imm32/inouts
13081     0/imm32/no-outputs
13082     0/imm32/no-outputs
13083     0x11/imm32/alloc-id:fake
13084     _string_3d_compare_eax_with/imm32/subx-name
13085     0/imm32/no-rm32
13086     0/imm32/no-r32
13087     2/imm32/imm32-is-second-inout
13088     0/imm32/no-disp32
13089     0/imm32/output-is-write-only
13090     0x11/imm32/alloc-id:fake
13091     _Primitive-compare-reg-with-literal/imm32/next
13092 _Primitive-compare-reg-with-literal:  # (payload primitive)
13093     0x11/imm32/alloc-id:fake:payload
13094     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
13095     0x11/imm32/alloc-id:fake
13096     _string-compare/imm32/name
13097     0x11/imm32/alloc-id:fake
13098     Int-var-in-register-and-literal/imm32/inouts
13099     0/imm32/no-outputs
13100     0/imm32/no-outputs
13101     0x11/imm32/alloc-id:fake
13102     _string_81_subop_compare/imm32/subx-name
13103     1/imm32/rm32-is-first-inout
13104     0/imm32/no-r32
13105     2/imm32/imm32-is-second-inout
13106     0/imm32/no-disp32
13107     0/imm32/output-is-write-only
13108     0x11/imm32/alloc-id:fake
13109     _Primitive-compare-mem-with-literal/imm32/next
13110 _Primitive-compare-mem-with-literal:  # (payload primitive)
13111     0x11/imm32/alloc-id:fake:payload
13112     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
13113     0x11/imm32/alloc-id:fake
13114     _string-compare/imm32/name
13115     0x11/imm32/alloc-id:fake
13116     Int-var-and-literal/imm32/inouts
13117     0/imm32/no-outputs
13118     0/imm32/no-outputs
13119     0x11/imm32/alloc-id:fake
13120     _string_81_subop_compare/imm32/subx-name
13121     1/imm32/rm32-is-first-inout
13122     0/imm32/no-r32
13123     2/imm32/imm32-is-second-inout
13124     0/imm32/no-disp32
13125     0/imm32/output-is-write-only
13126     0x11/imm32/alloc-id:fake
13127     _Primitive-multiply-reg-by-reg/imm32/next
13128 # - multiply
13129 _Primitive-multiply-reg-by-reg:  # (payload primitive)
13130     0x11/imm32/alloc-id:fake:payload
13131     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
13132     0x11/imm32/alloc-id:fake
13133     _string-multiply/imm32/name
13134     0x11/imm32/alloc-id:fake
13135     Single-int-var-in-some-register/imm32/inouts
13136     0x11/imm32/alloc-id:fake
13137     Single-int-var-in-some-register/imm32/outputs
13138     0x11/imm32/alloc-id:fake
13139     _string_0f_af_multiply/imm32/subx-name
13140     1/imm32/rm32-is-first-inout
13141     3/imm32/r32-is-first-output
13142     0/imm32/no-imm32
13143     0/imm32/no-disp32
13144     0/imm32/output-is-write-only
13145     0x11/imm32/alloc-id:fake
13146     _Primitive-multiply-reg-by-mem/imm32/next
13147 _Primitive-multiply-reg-by-mem:  # (payload primitive)
13148     0x11/imm32/alloc-id:fake:payload
13149     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
13150     0x11/imm32/alloc-id:fake
13151     _string-multiply/imm32/name
13152     0x11/imm32/alloc-id:fake
13153     Single-int-var-in-mem/imm32/inouts
13154     0x11/imm32/alloc-id:fake
13155     Single-int-var-in-some-register/imm32/outputs
13156     0x11/imm32/alloc-id:fake
13157     _string_0f_af_multiply/imm32/subx-name
13158     1/imm32/rm32-is-first-inout
13159     3/imm32/r32-is-first-output
13160     0/imm32/no-imm32
13161     0/imm32/no-disp32
13162     0/imm32/output-is-write-only
13163     0x11/imm32/alloc-id:fake
13164     _Primitive-break-if-addr</imm32/next
13165 # - branches
13166 _Primitive-break-if-addr<:  # (payload primitive)
13167     0x11/imm32/alloc-id:fake:payload
13168     0x11/imm32/alloc-id:fake
13169     _string-break-if-addr</imm32/name
13170     0/imm32/no-inouts
13171     0/imm32/no-inouts
13172     0/imm32/no-outputs
13173     0/imm32/no-outputs
13174     0x11/imm32/alloc-id:fake
13175     _string_0f_82_jump_break/imm32/subx-name
13176     0/imm32/no-rm32
13177     0/imm32/no-r32
13178     0/imm32/no-imm32
13179     0/imm32/no-disp32
13180     0/imm32/no-output
13181     0x11/imm32/alloc-id:fake
13182     _Primitive-break-if-addr>=/imm32/next
13183 _Primitive-break-if-addr>=:  # (payload primitive)
13184     0x11/imm32/alloc-id:fake:payload
13185     0x11/imm32/alloc-id:fake
13186     _string-break-if-addr>=/imm32/name
13187     0/imm32/no-inouts
13188     0/imm32/no-inouts
13189     0/imm32/no-outputs
13190     0/imm32/no-outputs
13191     0x11/imm32/alloc-id:fake
13192     _string_0f_83_jump_break/imm32/subx-name
13193     0/imm32/no-rm32
13194     0/imm32/no-r32
13195     0/imm32/no-imm32
13196     0/imm32/no-disp32
13197     0/imm32/no-output
13198     0x11/imm32/alloc-id:fake
13199     _Primitive-break-if-=/imm32/next
13200 _Primitive-break-if-=:  # (payload primitive)
13201     0x11/imm32/alloc-id:fake:payload
13202     0x11/imm32/alloc-id:fake
13203     _string-break-if-=/imm32/name
13204     0/imm32/no-inouts
13205     0/imm32/no-inouts
13206     0/imm32/no-outputs
13207     0/imm32/no-outputs
13208     0x11/imm32/alloc-id:fake
13209     _string_0f_84_jump_break/imm32/subx-name
13210     0/imm32/no-rm32
13211     0/imm32/no-r32
13212     0/imm32/no-imm32
13213     0/imm32/no-disp32
13214     0/imm32/no-output
13215     0x11/imm32/alloc-id:fake
13216     _Primitive-break-if-!=/imm32/next
13217 _Primitive-break-if-!=:  # (payload primitive)
13218     0x11/imm32/alloc-id:fake:payload
13219     0x11/imm32/alloc-id:fake
13220     _string-break-if-!=/imm32/name
13221     0/imm32/no-inouts
13222     0/imm32/no-inouts
13223     0/imm32/no-outputs
13224     0/imm32/no-outputs
13225     0x11/imm32/alloc-id:fake
13226     _string_0f_85_jump_break/imm32/subx-name
13227     0/imm32/no-rm32
13228     0/imm32/no-r32
13229     0/imm32/no-imm32
13230     0/imm32/no-disp32
13231     0/imm32/no-output
13232     0x11/imm32/alloc-id:fake
13233     _Primitive-break-if-addr<=/imm32/next
13234 _Primitive-break-if-addr<=:  # (payload primitive)
13235     0x11/imm32/alloc-id:fake:payload
13236     0x11/imm32/alloc-id:fake
13237     _string-break-if-addr<=/imm32/name
13238     0/imm32/no-inouts
13239     0/imm32/no-inouts
13240     0/imm32/no-outputs
13241     0/imm32/no-outputs
13242     0x11/imm32/alloc-id:fake
13243     _string_0f_86_jump_break/imm32/subx-name
13244     0/imm32/no-rm32
13245     0/imm32/no-r32
13246     0/imm32/no-imm32
13247     0/imm32/no-disp32
13248     0/imm32/no-output
13249     0x11/imm32/alloc-id:fake
13250     _Primitive-break-if-addr>/imm32/next
13251 _Primitive-break-if-addr>:  # (payload primitive)
13252     0x11/imm32/alloc-id:fake:payload
13253     0x11/imm32/alloc-id:fake
13254     _string-break-if-addr>/imm32/name
13255     0/imm32/no-inouts
13256     0/imm32/no-inouts
13257     0/imm32/no-outputs
13258     0/imm32/no-outputs
13259     0x11/imm32/alloc-id:fake
13260     _string_0f_87_jump_break/imm32/subx-name
13261     0/imm32/no-rm32
13262     0/imm32/no-r32
13263     0/imm32/no-imm32
13264     0/imm32/no-disp32
13265     0/imm32/no-output
13266     0x11/imm32/alloc-id:fake
13267     _Primitive-break-if-</imm32/next
13268 _Primitive-break-if-<:  # (payload primitive)
13269     0x11/imm32/alloc-id:fake:payload
13270     0x11/imm32/alloc-id:fake
13271     _string-break-if-</imm32/name
13272     0/imm32/no-inouts
13273     0/imm32/no-inouts
13274     0/imm32/no-outputs
13275     0/imm32/no-outputs
13276     0x11/imm32/alloc-id:fake
13277     _string_0f_8c_jump_break/imm32/subx-name
13278     0/imm32/no-rm32
13279     0/imm32/no-r32
13280     0/imm32/no-imm32
13281     0/imm32/no-disp32
13282     0/imm32/no-output
13283     0x11/imm32/alloc-id:fake
13284     _Primitive-break-if->=/imm32/next
13285 _Primitive-break-if->=:  # (payload primitive)
13286     0x11/imm32/alloc-id:fake:payload
13287     0x11/imm32/alloc-id:fake
13288     _string-break-if->=/imm32/name
13289     0/imm32/no-inouts
13290     0/imm32/no-inouts
13291     0/imm32/no-outputs
13292     0/imm32/no-outputs
13293     0x11/imm32/alloc-id:fake
13294     _string_0f_8d_jump_break/imm32/subx-name
13295     0/imm32/no-rm32
13296     0/imm32/no-r32
13297     0/imm32/no-imm32
13298     0/imm32/no-disp32
13299     0/imm32/no-output
13300     0x11/imm32/alloc-id:fake
13301     _Primitive-break-if-<=/imm32/next
13302 _Primitive-break-if-<=:  # (payload primitive)
13303     0x11/imm32/alloc-id:fake:payload
13304     0x11/imm32/alloc-id:fake
13305     _string-break-if-<=/imm32/name
13306     0/imm32/no-inouts
13307     0/imm32/no-inouts
13308     0/imm32/no-outputs
13309     0/imm32/no-outputs
13310     0x11/imm32/alloc-id:fake
13311     _string_0f_8e_jump_break/imm32/subx-name
13312     0/imm32/no-rm32
13313     0/imm32/no-r32
13314     0/imm32/no-imm32
13315     0/imm32/no-disp32
13316     0/imm32/no-output
13317     0x11/imm32/alloc-id:fake
13318     _Primitive-break-if->/imm32/next
13319 _Primitive-break-if->:  # (payload primitive)
13320     0x11/imm32/alloc-id:fake:payload
13321     0x11/imm32/alloc-id:fake
13322     _string-break-if->/imm32/name
13323     0/imm32/no-inouts
13324     0/imm32/no-inouts
13325     0/imm32/no-outputs
13326     0/imm32/no-outputs
13327     0x11/imm32/alloc-id:fake
13328     _string_0f_8f_jump_break/imm32/subx-name
13329     0/imm32/no-rm32
13330     0/imm32/no-r32
13331     0/imm32/no-imm32
13332     0/imm32/no-disp32
13333     0/imm32/no-output
13334     0x11/imm32/alloc-id:fake
13335     _Primitive-break/imm32/next
13336 _Primitive-break:  # (payload primitive)
13337     0x11/imm32/alloc-id:fake:payload
13338     0x11/imm32/alloc-id:fake
13339     _string-break/imm32/name
13340     0/imm32/no-inouts
13341     0/imm32/no-inouts
13342     0/imm32/no-outputs
13343     0/imm32/no-outputs
13344     0x11/imm32/alloc-id:fake
13345     _string_e9_jump_break/imm32/subx-name
13346     0/imm32/no-rm32
13347     0/imm32/no-r32
13348     0/imm32/no-imm32
13349     0/imm32/no-disp32
13350     0/imm32/no-output
13351     0x11/imm32/alloc-id:fake
13352     _Primitive-loop-if-addr</imm32/next
13353 _Primitive-loop-if-addr<:  # (payload primitive)
13354     0x11/imm32/alloc-id:fake:payload
13355     0x11/imm32/alloc-id:fake
13356     _string-loop-if-addr</imm32/name
13357     0/imm32/no-inouts
13358     0/imm32/no-inouts
13359     0/imm32/no-outputs
13360     0/imm32/no-outputs
13361     0x11/imm32/alloc-id:fake
13362     _string_0f_82_jump_loop/imm32/subx-name
13363     0/imm32/no-rm32
13364     0/imm32/no-r32
13365     0/imm32/no-imm32
13366     0/imm32/no-disp32
13367     0/imm32/no-output
13368     0x11/imm32/alloc-id:fake
13369     _Primitive-loop-if-addr>=/imm32/next
13370 _Primitive-loop-if-addr>=:  # (payload primitive)
13371     0x11/imm32/alloc-id:fake:payload
13372     0x11/imm32/alloc-id:fake
13373     _string-loop-if-addr>=/imm32/name
13374     0/imm32/no-inouts
13375     0/imm32/no-inouts
13376     0/imm32/no-outputs
13377     0/imm32/no-outputs
13378     0x11/imm32/alloc-id:fake
13379     _string_0f_83_jump_loop/imm32/subx-name
13380     0/imm32/no-rm32
13381     0/imm32/no-r32
13382     0/imm32/no-imm32
13383     0/imm32/no-disp32
13384     0/imm32/no-output
13385     0x11/imm32/alloc-id:fake
13386     _Primitive-loop-if-=/imm32/next
13387 _Primitive-loop-if-=:  # (payload primitive)
13388     0x11/imm32/alloc-id:fake:payload
13389     0x11/imm32/alloc-id:fake
13390     _string-loop-if-=/imm32/name
13391     0/imm32/no-inouts
13392     0/imm32/no-inouts
13393     0/imm32/no-outputs
13394     0/imm32/no-outputs
13395     0x11/imm32/alloc-id:fake
13396     _string_0f_84_jump_loop/imm32/subx-name
13397     0/imm32/no-rm32
13398     0/imm32/no-r32
13399     0/imm32/no-imm32
13400     0/imm32/no-disp32
13401     0/imm32/no-output
13402     0x11/imm32/alloc-id:fake
13403     _Primitive-loop-if-!=/imm32/next
13404 _Primitive-loop-if-!=:  # (payload primitive)
13405     0x11/imm32/alloc-id:fake:payload
13406     0x11/imm32/alloc-id:fake
13407     _string-loop-if-!=/imm32/name
13408     0/imm32/no-inouts
13409     0/imm32/no-inouts
13410     0/imm32/no-outputs
13411     0/imm32/no-outputs
13412     0x11/imm32/alloc-id:fake
13413     _string_0f_85_jump_loop/imm32/subx-name
13414     0/imm32/no-rm32
13415     0/imm32/no-r32
13416     0/imm32/no-imm32
13417     0/imm32/no-disp32
13418     0/imm32/no-output
13419     0x11/imm32/alloc-id:fake
13420     _Primitive-loop-if-addr<=/imm32/next
13421 _Primitive-loop-if-addr<=:  # (payload primitive)
13422     0x11/imm32/alloc-id:fake:payload
13423     0x11/imm32/alloc-id:fake
13424     _string-loop-if-addr<=/imm32/name
13425     0/imm32/no-inouts
13426     0/imm32/no-inouts
13427     0/imm32/no-outputs
13428     0/imm32/no-outputs
13429     0x11/imm32/alloc-id:fake
13430     _string_0f_86_jump_loop/imm32/subx-name
13431     0/imm32/no-rm32
13432     0/imm32/no-r32
13433     0/imm32/no-imm32
13434     0/imm32/no-disp32
13435     0/imm32/no-output
13436     0x11/imm32/alloc-id:fake
13437     _Primitive-loop-if-addr>/imm32/next
13438 _Primitive-loop-if-addr>:  # (payload primitive)
13439     0x11/imm32/alloc-id:fake:payload
13440     0x11/imm32/alloc-id:fake
13441     _string-loop-if-addr>/imm32/name
13442     0/imm32/no-inouts
13443     0/imm32/no-inouts
13444     0/imm32/no-outputs
13445     0/imm32/no-outputs
13446     0x11/imm32/alloc-id:fake
13447     _string_0f_87_jump_loop/imm32/subx-name
13448     0/imm32/no-rm32
13449     0/imm32/no-r32
13450     0/imm32/no-imm32
13451     0/imm32/no-disp32
13452     0/imm32/no-output
13453     0x11/imm32/alloc-id:fake
13454     _Primitive-loop-if-</imm32/next
13455 _Primitive-loop-if-<:  # (payload primitive)
13456     0x11/imm32/alloc-id:fake:payload
13457     0x11/imm32/alloc-id:fake
13458     _string-loop-if-</imm32/name
13459     0/imm32/no-inouts
13460     0/imm32/no-inouts
13461     0/imm32/no-outputs
13462     0/imm32/no-outputs
13463     0x11/imm32/alloc-id:fake
13464     _string_0f_8c_jump_loop/imm32/subx-name
13465     0/imm32/no-rm32
13466     0/imm32/no-r32
13467     0/imm32/no-imm32
13468     0/imm32/no-disp32
13469     0/imm32/no-output
13470     0x11/imm32/alloc-id:fake
13471     _Primitive-loop-if->=/imm32/next
13472 _Primitive-loop-if->=:  # (payload primitive)
13473     0x11/imm32/alloc-id:fake:payload
13474     0x11/imm32/alloc-id:fake
13475     _string-loop-if->=/imm32/name
13476     0/imm32/no-inouts
13477     0/imm32/no-inouts
13478     0/imm32/no-outputs
13479     0/imm32/no-outputs
13480     0x11/imm32/alloc-id:fake
13481     _string_0f_8d_jump_loop/imm32/subx-name
13482     0/imm32/no-rm32
13483     0/imm32/no-r32
13484     0/imm32/no-imm32
13485     0/imm32/no-disp32
13486     0/imm32/no-output
13487     0x11/imm32/alloc-id:fake
13488     _Primitive-loop-if-<=/imm32/next
13489 _Primitive-loop-if-<=:  # (payload primitive)
13490     0x11/imm32/alloc-id:fake:payload
13491     0x11/imm32/alloc-id:fake
13492     _string-loop-if-<=/imm32/name
13493     0/imm32/no-inouts
13494     0/imm32/no-inouts
13495     0/imm32/no-outputs
13496     0/imm32/no-outputs
13497     0x11/imm32/alloc-id:fake
13498     _string_0f_8e_jump_loop/imm32/subx-name
13499     0/imm32/no-rm32
13500     0/imm32/no-r32
13501     0/imm32/no-imm32
13502     0/imm32/no-disp32
13503     0/imm32/no-output
13504     0x11/imm32/alloc-id:fake
13505     _Primitive-loop-if->/imm32/next
13506 _Primitive-loop-if->:  # (payload primitive)
13507     0x11/imm32/alloc-id:fake:payload
13508     0x11/imm32/alloc-id:fake
13509     _string-loop-if->/imm32/name
13510     0/imm32/no-inouts
13511     0/imm32/no-inouts
13512     0/imm32/no-outputs
13513     0/imm32/no-outputs
13514     0x11/imm32/alloc-id:fake
13515     _string_0f_8f_jump_loop/imm32/subx-name
13516     0/imm32/no-rm32
13517     0/imm32/no-r32
13518     0/imm32/no-imm32
13519     0/imm32/no-disp32
13520     0/imm32/no-output
13521     0x11/imm32/alloc-id:fake
13522     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
13523 _Primitive-loop:  # (payload primitive)
13524     0x11/imm32/alloc-id:fake:payload
13525     0x11/imm32/alloc-id:fake
13526     _string-loop/imm32/name
13527     0/imm32/no-inouts
13528     0/imm32/no-inouts
13529     0/imm32/no-outputs
13530     0/imm32/no-outputs
13531     0x11/imm32/alloc-id:fake
13532     _string_e9_jump_loop/imm32/subx-name
13533     0/imm32/no-rm32
13534     0/imm32/no-r32
13535     0/imm32/no-imm32
13536     0/imm32/no-disp32
13537     0/imm32/no-output
13538     0x11/imm32/alloc-id:fake
13539     _Primitive-break-if-addr<-named/imm32/next
13540 # - branches to named blocks
13541 _Primitive-break-if-addr<-named:  # (payload primitive)
13542     0x11/imm32/alloc-id:fake:payload
13543     0x11/imm32/alloc-id:fake
13544     _string-break-if-addr</imm32/name
13545     0x11/imm32/alloc-id:fake
13546     Single-lit-var/imm32/inouts
13547     0/imm32/no-outputs
13548     0/imm32/no-outputs
13549     0x11/imm32/alloc-id:fake
13550     _string_0f_82_jump_label/imm32/subx-name
13551     0/imm32/no-rm32
13552     0/imm32/no-r32
13553     0/imm32/no-imm32
13554     1/imm32/disp32-is-first-inout
13555     0/imm32/no-output
13556     0x11/imm32/alloc-id:fake
13557     _Primitive-break-if-addr>=-named/imm32/next
13558 _Primitive-break-if-addr>=-named:  # (payload primitive)
13559     0x11/imm32/alloc-id:fake:payload
13560     0x11/imm32/alloc-id:fake
13561     _string-break-if-addr>=/imm32/name
13562     0x11/imm32/alloc-id:fake
13563     Single-lit-var/imm32/inouts
13564     0/imm32/no-outputs
13565     0/imm32/no-outputs
13566     0x11/imm32/alloc-id:fake
13567     _string_0f_83_jump_label/imm32/subx-name
13568     0/imm32/no-rm32
13569     0/imm32/no-r32
13570     0/imm32/no-imm32
13571     1/imm32/disp32-is-first-inout
13572     0/imm32/no-output
13573     0x11/imm32/alloc-id:fake
13574     _Primitive-break-if-=-named/imm32/next
13575 _Primitive-break-if-=-named:  # (payload primitive)
13576     0x11/imm32/alloc-id:fake:payload
13577     0x11/imm32/alloc-id:fake
13578     _string-break-if-=/imm32/name
13579     0x11/imm32/alloc-id:fake
13580     Single-lit-var/imm32/inouts
13581     0/imm32/no-outputs
13582     0/imm32/no-outputs
13583     0x11/imm32/alloc-id:fake
13584     _string_0f_84_jump_label/imm32/subx-name
13585     0/imm32/no-rm32
13586     0/imm32/no-r32
13587     0/imm32/no-imm32
13588     1/imm32/disp32-is-first-inout
13589     0/imm32/no-output
13590     0x11/imm32/alloc-id:fake
13591     _Primitive-break-if-!=-named/imm32/next
13592 _Primitive-break-if-!=-named:  # (payload primitive)
13593     0x11/imm32/alloc-id:fake:payload
13594     0x11/imm32/alloc-id:fake
13595     _string-break-if-!=/imm32/name
13596     0x11/imm32/alloc-id:fake
13597     Single-lit-var/imm32/inouts
13598     0/imm32/no-outputs
13599     0/imm32/no-outputs
13600     0x11/imm32/alloc-id:fake
13601     _string_0f_85_jump_label/imm32/subx-name
13602     0/imm32/no-rm32
13603     0/imm32/no-r32
13604     0/imm32/no-imm32
13605     1/imm32/disp32-is-first-inout
13606     0/imm32/no-output
13607     0x11/imm32/alloc-id:fake
13608     _Primitive-break-if-addr<=-named/imm32/next
13609 _Primitive-break-if-addr<=-named:  # (payload primitive)
13610     0x11/imm32/alloc-id:fake:payload
13611     0x11/imm32/alloc-id:fake
13612     _string-break-if-addr<=/imm32/name
13613     0x11/imm32/alloc-id:fake
13614     Single-lit-var/imm32/inouts
13615     0/imm32/no-outputs
13616     0/imm32/no-outputs
13617     0x11/imm32/alloc-id:fake
13618     _string_0f_86_jump_label/imm32/subx-name
13619     0/imm32/no-rm32
13620     0/imm32/no-r32
13621     0/imm32/no-imm32
13622     1/imm32/disp32-is-first-inout
13623     0/imm32/no-output
13624     0x11/imm32/alloc-id:fake
13625     _Primitive-break-if-addr>-named/imm32/next
13626 _Primitive-break-if-addr>-named:  # (payload primitive)
13627     0x11/imm32/alloc-id:fake:payload
13628     0x11/imm32/alloc-id:fake
13629     _string-break-if-addr>/imm32/name
13630     0x11/imm32/alloc-id:fake
13631     Single-lit-var/imm32/inouts
13632     0/imm32/no-outputs
13633     0/imm32/no-outputs
13634     0x11/imm32/alloc-id:fake
13635     _string_0f_87_jump_label/imm32/subx-name
13636     0/imm32/no-rm32
13637     0/imm32/no-r32
13638     0/imm32/no-imm32
13639     1/imm32/disp32-is-first-inout
13640     0/imm32/no-output
13641     0x11/imm32/alloc-id:fake
13642     _Primitive-break-if-<-named/imm32/next
13643 _Primitive-break-if-<-named:  # (payload primitive)
13644     0x11/imm32/alloc-id:fake:payload
13645     0x11/imm32/alloc-id:fake
13646     _string-break-if-</imm32/name
13647     0x11/imm32/alloc-id:fake
13648     Single-lit-var/imm32/inouts
13649     0/imm32/no-outputs
13650     0/imm32/no-outputs
13651     0x11/imm32/alloc-id:fake
13652     _string_0f_8c_jump_label/imm32/subx-name
13653     0/imm32/no-rm32
13654     0/imm32/no-r32
13655     0/imm32/no-imm32
13656     1/imm32/disp32-is-first-inout
13657     0/imm32/no-output
13658     0x11/imm32/alloc-id:fake
13659     _Primitive-break-if->=-named/imm32/next
13660 _Primitive-break-if->=-named:  # (payload primitive)
13661     0x11/imm32/alloc-id:fake:payload
13662     0x11/imm32/alloc-id:fake
13663     _string-break-if->=/imm32/name
13664     0x11/imm32/alloc-id:fake
13665     Single-lit-var/imm32/inouts
13666     0/imm32/no-outputs
13667     0/imm32/no-outputs
13668     0x11/imm32/alloc-id:fake
13669     _string_0f_8d_jump_label/imm32/subx-name
13670     0/imm32/no-rm32
13671     0/imm32/no-r32
13672     0/imm32/no-imm32
13673     1/imm32/disp32-is-first-inout
13674     0/imm32/no-output
13675     0x11/imm32/alloc-id:fake
13676     _Primitive-break-if-<=-named/imm32/next
13677 _Primitive-break-if-<=-named:  # (payload primitive)
13678     0x11/imm32/alloc-id:fake:payload
13679     0x11/imm32/alloc-id:fake
13680     _string-break-if-<=/imm32/name
13681     0x11/imm32/alloc-id:fake
13682     Single-lit-var/imm32/inouts
13683     0/imm32/no-outputs
13684     0/imm32/no-outputs
13685     0x11/imm32/alloc-id:fake
13686     _string_0f_8e_jump_label/imm32/subx-name
13687     0/imm32/no-rm32
13688     0/imm32/no-r32
13689     0/imm32/no-imm32
13690     1/imm32/disp32-is-first-inout
13691     0/imm32/no-output
13692     0x11/imm32/alloc-id:fake
13693     _Primitive-break-if->-named/imm32/next
13694 _Primitive-break-if->-named:  # (payload primitive)
13695     0x11/imm32/alloc-id:fake:payload
13696     0x11/imm32/alloc-id:fake
13697     _string-break-if->/imm32/name
13698     0x11/imm32/alloc-id:fake
13699     Single-lit-var/imm32/inouts
13700     0/imm32/no-outputs
13701     0/imm32/no-outputs
13702     0x11/imm32/alloc-id:fake
13703     _string_0f_8f_jump_label/imm32/subx-name
13704     0/imm32/no-rm32
13705     0/imm32/no-r32
13706     0/imm32/no-imm32
13707     1/imm32/disp32-is-first-inout
13708     0/imm32/no-output
13709     0x11/imm32/alloc-id:fake
13710     _Primitive-break-named/imm32/next
13711 _Primitive-break-named:  # (payload primitive)
13712     0x11/imm32/alloc-id:fake:payload
13713     0x11/imm32/alloc-id:fake
13714     _string-break/imm32/name
13715     0x11/imm32/alloc-id:fake
13716     Single-lit-var/imm32/inouts
13717     0/imm32/no-outputs
13718     0/imm32/no-outputs
13719     0x11/imm32/alloc-id:fake
13720     _string_e9_jump_label/imm32/subx-name
13721     0/imm32/no-rm32
13722     0/imm32/no-r32
13723     0/imm32/no-imm32
13724     1/imm32/disp32-is-first-inout
13725     0/imm32/no-output
13726     0x11/imm32/alloc-id:fake
13727     _Primitive-loop-if-addr<-named/imm32/next
13728 _Primitive-loop-if-addr<-named:  # (payload primitive)
13729     0x11/imm32/alloc-id:fake:payload
13730     0x11/imm32/alloc-id:fake
13731     _string-loop-if-addr</imm32/name
13732     0x11/imm32/alloc-id:fake
13733     Single-lit-var/imm32/inouts
13734     0/imm32/no-outputs
13735     0/imm32/no-outputs
13736     0x11/imm32/alloc-id:fake
13737     _string_0f_82_jump_label/imm32/subx-name
13738     0/imm32/no-rm32
13739     0/imm32/no-r32
13740     0/imm32/no-imm32
13741     1/imm32/disp32-is-first-inout
13742     0/imm32/no-output
13743     0x11/imm32/alloc-id:fake
13744     _Primitive-loop-if-addr>=-named/imm32/next
13745 _Primitive-loop-if-addr>=-named:  # (payload primitive)
13746     0x11/imm32/alloc-id:fake:payload
13747     0x11/imm32/alloc-id:fake
13748     _string-loop-if-addr>=/imm32/name
13749     0x11/imm32/alloc-id:fake
13750     Single-lit-var/imm32/inouts
13751     0/imm32/no-outputs
13752     0/imm32/no-outputs
13753     0x11/imm32/alloc-id:fake
13754     _string_0f_83_jump_label/imm32/subx-name
13755     0/imm32/no-rm32
13756     0/imm32/no-r32
13757     0/imm32/no-imm32
13758     1/imm32/disp32-is-first-inout
13759     0/imm32/no-output
13760     0x11/imm32/alloc-id:fake
13761     _Primitive-loop-if-=-named/imm32/next
13762 _Primitive-loop-if-=-named:  # (payload primitive)
13763     0x11/imm32/alloc-id:fake:payload
13764     0x11/imm32/alloc-id:fake
13765     _string-loop-if-=/imm32/name
13766     0x11/imm32/alloc-id:fake
13767     Single-lit-var/imm32/inouts
13768     0/imm32/no-outputs
13769     0/imm32/no-outputs
13770     0x11/imm32/alloc-id:fake
13771     _string_0f_84_jump_label/imm32/subx-name
13772     0/imm32/no-rm32
13773     0/imm32/no-r32
13774     0/imm32/no-imm32
13775     1/imm32/disp32-is-first-inout
13776     0/imm32/no-output
13777     0x11/imm32/alloc-id:fake
13778     _Primitive-loop-if-!=-named/imm32/next
13779 _Primitive-loop-if-!=-named:  # (payload primitive)
13780     0x11/imm32/alloc-id:fake:payload
13781     0x11/imm32/alloc-id:fake
13782     _string-loop-if-!=/imm32/name
13783     0x11/imm32/alloc-id:fake
13784     Single-lit-var/imm32/inouts
13785     0/imm32/no-outputs
13786     0/imm32/no-outputs
13787     0x11/imm32/alloc-id:fake
13788     _string_0f_85_jump_label/imm32/subx-name
13789     0/imm32/no-rm32
13790     0/imm32/no-r32
13791     0/imm32/no-imm32
13792     1/imm32/disp32-is-first-inout
13793     0/imm32/no-output
13794     0x11/imm32/alloc-id:fake
13795     _Primitive-loop-if-addr<=-named/imm32/next
13796 _Primitive-loop-if-addr<=-named:  # (payload primitive)
13797     0x11/imm32/alloc-id:fake:payload
13798     0x11/imm32/alloc-id:fake
13799     _string-loop-if-addr<=/imm32/name
13800     0x11/imm32/alloc-id:fake
13801     Single-lit-var/imm32/inouts
13802     0/imm32/no-outputs
13803     0/imm32/no-outputs
13804     0x11/imm32/alloc-id:fake
13805     _string_0f_86_jump_label/imm32/subx-name
13806     0/imm32/no-rm32
13807     0/imm32/no-r32
13808     0/imm32/no-imm32
13809     1/imm32/disp32-is-first-inout
13810     0/imm32/no-output
13811     0x11/imm32/alloc-id:fake
13812     _Primitive-loop-if-addr>-named/imm32/next
13813 _Primitive-loop-if-addr>-named:  # (payload primitive)
13814     0x11/imm32/alloc-id:fake:payload
13815     0x11/imm32/alloc-id:fake
13816     _string-loop-if-addr>/imm32/name
13817     0x11/imm32/alloc-id:fake
13818     Single-lit-var/imm32/inouts
13819     0/imm32/no-outputs
13820     0/imm32/no-outputs
13821     0x11/imm32/alloc-id:fake
13822     _string_0f_87_jump_label/imm32/subx-name
13823     0/imm32/no-rm32
13824     0/imm32/no-r32
13825     0/imm32/no-imm32
13826     1/imm32/disp32-is-first-inout
13827     0/imm32/no-output
13828     0x11/imm32/alloc-id:fake
13829     _Primitive-loop-if-<-named/imm32/next
13830 _Primitive-loop-if-<-named:  # (payload primitive)
13831     0x11/imm32/alloc-id:fake:payload
13832     0x11/imm32/alloc-id:fake
13833     _string-loop-if-</imm32/name
13834     0x11/imm32/alloc-id:fake
13835     Single-lit-var/imm32/inouts
13836     0/imm32/no-outputs
13837     0/imm32/no-outputs
13838     0x11/imm32/alloc-id:fake
13839     _string_0f_8c_jump_label/imm32/subx-name
13840     0/imm32/no-rm32
13841     0/imm32/no-r32
13842     0/imm32/no-imm32
13843     1/imm32/disp32-is-first-inout
13844     0/imm32/no-output
13845     0x11/imm32/alloc-id:fake
13846     _Primitive-loop-if->=-named/imm32/next
13847 _Primitive-loop-if->=-named:  # (payload primitive)
13848     0x11/imm32/alloc-id:fake:payload
13849     0x11/imm32/alloc-id:fake
13850     _string-loop-if->=/imm32/name
13851     0x11/imm32/alloc-id:fake
13852     Single-lit-var/imm32/inouts
13853     0/imm32/no-outputs
13854     0/imm32/no-outputs
13855     0x11/imm32/alloc-id:fake
13856     _string_0f_8d_jump_label/imm32/subx-name
13857     0/imm32/no-rm32
13858     0/imm32/no-r32
13859     0/imm32/no-imm32
13860     1/imm32/disp32-is-first-inout
13861     0/imm32/no-output
13862     0x11/imm32/alloc-id:fake
13863     _Primitive-loop-if-<=-named/imm32/next
13864 _Primitive-loop-if-<=-named:  # (payload primitive)
13865     0x11/imm32/alloc-id:fake:payload
13866     0x11/imm32/alloc-id:fake
13867     _string-loop-if-<=/imm32/name
13868     0x11/imm32/alloc-id:fake
13869     Single-lit-var/imm32/inouts
13870     0/imm32/no-outputs
13871     0/imm32/no-outputs
13872     0x11/imm32/alloc-id:fake
13873     _string_0f_8e_jump_label/imm32/subx-name
13874     0/imm32/no-rm32
13875     0/imm32/no-r32
13876     0/imm32/no-imm32
13877     1/imm32/disp32-is-first-inout
13878     0/imm32/no-output
13879     0x11/imm32/alloc-id:fake
13880     _Primitive-loop-if->-named/imm32/next
13881 _Primitive-loop-if->-named:  # (payload primitive)
13882     0x11/imm32/alloc-id:fake:payload
13883     0x11/imm32/alloc-id:fake
13884     _string-loop-if->/imm32/name
13885     0x11/imm32/alloc-id:fake
13886     Single-lit-var/imm32/inouts
13887     0/imm32/no-outputs
13888     0/imm32/no-outputs
13889     0x11/imm32/alloc-id:fake
13890     _string_0f_8f_jump_label/imm32/subx-name
13891     0/imm32/no-rm32
13892     0/imm32/no-r32
13893     0/imm32/no-imm32
13894     1/imm32/disp32-is-first-inout
13895     0/imm32/no-output
13896     0x11/imm32/alloc-id:fake
13897     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
13898 _Primitive-loop-named:  # (payload primitive)
13899     0x11/imm32/alloc-id:fake:payload
13900     0x11/imm32/alloc-id:fake
13901     _string-loop/imm32/name
13902     0x11/imm32/alloc-id:fake
13903     Single-lit-var/imm32/inouts
13904     0/imm32/no-outputs
13905     0/imm32/no-outputs
13906     0x11/imm32/alloc-id:fake
13907     _string_e9_jump_label/imm32/subx-name
13908     0/imm32/no-rm32
13909     0/imm32/no-r32
13910     0/imm32/no-imm32
13911     1/imm32/disp32-is-first-inout
13912     0/imm32/no-output
13913     0/imm32/next
13914     0/imm32/next
13915 
13916 # string literals for Mu instructions
13917 _string-add:  # (payload array byte)
13918     0x11/imm32/alloc-id:fake:payload
13919     # "add"
13920     0x3/imm32/size
13921     0x61/a 0x64/d 0x64/d
13922 _string-address:  # (payload array byte)
13923     0x11/imm32/alloc-id:fake:payload
13924     # "address"
13925     0x7/imm32/size
13926     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
13927 _string-add-to:  # (payload array byte)
13928     0x11/imm32/alloc-id:fake:payload
13929     # "add-to"
13930     0x6/imm32/size
13931     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
13932 _string-and:  # (payload array byte)
13933     0x11/imm32/alloc-id:fake:payload
13934     # "and"
13935     0x3/imm32/size
13936     0x61/a 0x6e/n 0x64/d
13937 _string-and-with:  # (payload array byte)
13938     0x11/imm32/alloc-id:fake:payload
13939     # "and-with"
13940     0x8/imm32/size
13941     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
13942 _string-break:  # (payload array byte)
13943     0x11/imm32/alloc-id:fake:payload
13944     # "break"
13945     0x5/imm32/size
13946     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
13947 _string-break-if-<:  # (payload array byte)
13948     0x11/imm32/alloc-id:fake:payload
13949     # "break-if-<"
13950     0xa/imm32/size
13951     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
13952 _string-break-if-<=:  # (payload array byte)
13953     0x11/imm32/alloc-id:fake:payload
13954     # "break-if-<="
13955     0xb/imm32/size
13956     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
13957 _string-break-if-=:  # (payload array byte)
13958     0x11/imm32/alloc-id:fake:payload
13959     # "break-if-="
13960     0xa/imm32/size
13961     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
13962 _string-break-if->:  # (payload array byte)
13963     0x11/imm32/alloc-id:fake:payload
13964     # "break-if->"
13965     0xa/imm32/size
13966     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
13967 _string-break-if->=:  # (payload array byte)
13968     0x11/imm32/alloc-id:fake:payload
13969     # "break-if->="
13970     0xb/imm32/size
13971     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
13972 _string-break-if-!=:  # (payload array byte)
13973     0x11/imm32/alloc-id:fake:payload
13974     # "break-if-!="
13975     0xb/imm32/size
13976     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
13977 _string-break-if-addr<:  # (payload array byte)
13978     0x11/imm32/alloc-id:fake:payload
13979     # "break-if-addr<"
13980     0xe/imm32/size
13981     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/<
13982 _string-break-if-addr<=:  # (payload array byte)
13983     0x11/imm32/alloc-id:fake:payload
13984     # "break-if-addr<="
13985     0xf/imm32/size
13986     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/=
13987 _string-break-if-addr>:  # (payload array byte)
13988     0x11/imm32/alloc-id:fake:payload
13989     # "break-if-addr>"
13990     0xe/imm32/size
13991     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/>
13992 _string-break-if-addr>=:  # (payload array byte)
13993     0x11/imm32/alloc-id:fake:payload
13994     # "break-if-addr>="
13995     0xf/imm32/size
13996     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/=
13997 _string-compare:  # (payload array byte)
13998     0x11/imm32/alloc-id:fake:payload
13999     # "compare"
14000     0x7/imm32/size
14001     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
14002 _string-copy:  # (payload array byte)
14003     0x11/imm32/alloc-id:fake:payload
14004     # "copy"
14005     0x4/imm32/size
14006     0x63/c 0x6f/o 0x70/p 0x79/y
14007 _string-copy-to:  # (payload array byte)
14008     0x11/imm32/alloc-id:fake:payload
14009     # "copy-to"
14010     0x7/imm32/size
14011     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
14012 _string-copy-byte:
14013     0x11/imm32/alloc-id:fake:payload
14014     # "copy-byte"
14015     0x9/imm32/size
14016     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
14017 _string-copy-byte-to:
14018     0x11/imm32/alloc-id:fake:payload
14019     # "copy-byte-to"
14020     0xc/imm32/size
14021     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
14022 _string-decrement:  # (payload array byte)
14023     0x11/imm32/alloc-id:fake:payload
14024     # "decrement"
14025     0x9/imm32/size
14026     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
14027 _string-increment:  # (payload array byte)
14028     0x11/imm32/alloc-id:fake:payload
14029     # "increment"
14030     0x9/imm32/size
14031     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
14032 _string-loop:  # (payload array byte)
14033     0x11/imm32/alloc-id:fake:payload
14034     # "loop"
14035     0x4/imm32/size
14036     0x6c/l 0x6f/o 0x6f/o 0x70/p
14037 _string-loop-if-<:  # (payload array byte)
14038     0x11/imm32/alloc-id:fake:payload
14039     # "loop-if-<"
14040     0x9/imm32/size
14041     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
14042 _string-loop-if-<=:  # (payload array byte)
14043     0x11/imm32/alloc-id:fake:payload
14044     # "loop-if-<="
14045     0xa/imm32/size
14046     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
14047 _string-loop-if-=:  # (payload array byte)
14048     0x11/imm32/alloc-id:fake:payload
14049     # "loop-if-="
14050     0x9/imm32/size
14051     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
14052 _string-loop-if->:  # (payload array byte)
14053     0x11/imm32/alloc-id:fake:payload
14054     # "loop-if->"
14055     0x9/imm32/size
14056     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
14057 _string-loop-if->=:  # (payload array byte)
14058     0x11/imm32/alloc-id:fake:payload
14059     # "loop-if->="
14060     0xa/imm32/size
14061     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
14062 _string-loop-if-!=:  # (payload array byte)
14063     0x11/imm32/alloc-id:fake:payload
14064     # "loop-if-!="
14065     0xa/imm32/size
14066     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
14067 _string-loop-if-addr<:  # (payload array byte)
14068     0x11/imm32/alloc-id:fake:payload
14069     # "loop-if-addr<"
14070     0xd/imm32/size
14071     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/<
14072 _string-loop-if-addr<=:  # (payload array byte)
14073     0x11/imm32/alloc-id:fake:payload
14074     # "loop-if-addr<="
14075     0xe/imm32/size
14076     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/=
14077 _string-loop-if-addr>:  # (payload array byte)
14078     0x11/imm32/alloc-id:fake:payload
14079     # "loop-if-addr>"
14080     0xd/imm32/size
14081     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/>
14082 _string-loop-if-addr>=:  # (payload array byte)
14083     0x11/imm32/alloc-id:fake:payload
14084     # "loop-if-addr>="
14085     0xe/imm32/size
14086     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/=
14087 _string-multiply:  # (payload array byte)
14088     0x11/imm32/alloc-id:fake:payload
14089     # "multiply"
14090     0x8/imm32/size
14091     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
14092 _string-or:  # (payload array byte)
14093     0x11/imm32/alloc-id:fake:payload
14094     # "or"
14095     0x2/imm32/size
14096     0x6f/o 0x72/r
14097 _string-or-with:  # (payload array byte)
14098     0x11/imm32/alloc-id:fake:payload
14099     # "or-with"
14100     0x7/imm32/size
14101     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14102 _string-subtract:  # (payload array byte)
14103     0x11/imm32/alloc-id:fake:payload
14104     # "subtract"
14105     0x8/imm32/size
14106     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
14107 _string-subtract-from:  # (payload array byte)
14108     0x11/imm32/alloc-id:fake:payload
14109     # "subtract-from"
14110     0xd/imm32/size
14111     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
14112 _string-xor:  # (payload array byte)
14113     0x11/imm32/alloc-id:fake:payload
14114     # "xor"
14115     0x3/imm32/size
14116     0x78/x 0x6f/o 0x72/r
14117 _string-xor-with:  # (payload array byte)
14118     0x11/imm32/alloc-id:fake:payload
14119     # "xor-with"
14120     0x8/imm32/size
14121     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14122 
14123 # string literals for SubX instructions
14124 _string_01_add_to:  # (payload array byte)
14125     0x11/imm32/alloc-id:fake:payload
14126     # "01/add-to"
14127     0x9/imm32/size
14128     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
14129 _string_03_add:  # (payload array byte)
14130     0x11/imm32/alloc-id:fake:payload
14131     # "03/add"
14132     0x6/imm32/size
14133     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
14134 _string_05_add_to_eax:  # (payload array byte)
14135     0x11/imm32/alloc-id:fake:payload
14136     # "05/add-to-eax"
14137     0xd/imm32/size
14138     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
14139 _string_09_or_with:  # (payload array byte)
14140     0x11/imm32/alloc-id:fake:payload
14141     # "09/or-with"
14142     0xa/imm32/size
14143     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14144 _string_0b_or:  # (payload array byte)
14145     0x11/imm32/alloc-id:fake:payload
14146     # "0b/or"
14147     0x5/imm32/size
14148     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
14149 _string_0d_or_with_eax:  # (payload array byte)
14150     0x11/imm32/alloc-id:fake:payload
14151     # "0d/or-with-eax"
14152     0xe/imm32/size
14153     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
14154 _string_0f_82_jump_label:  # (payload array byte)
14155     0x11/imm32/alloc-id:fake:payload
14156     # "0f 82/jump-if-addr<"
14157     0x13/imm32/size
14158     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/<
14159 _string_0f_82_jump_break:  # (payload array byte)
14160     0x11/imm32/alloc-id:fake:payload
14161     # "0f 82/jump-if-addr< break/disp32"
14162     0x20/imm32/size
14163     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
14164 _string_0f_82_jump_loop:  # (payload array byte)
14165     0x11/imm32/alloc-id:fake:payload
14166     # "0f 82/jump-if-addr< loop/disp32"
14167     0x1f/imm32/size
14168     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
14169 _string_0f_83_jump_label:  # (payload array byte)
14170     0x11/imm32/alloc-id:fake:payload
14171     # "0f 83/jump-if-addr>="
14172     0x14/imm32/size
14173     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/=
14174 _string_0f_83_jump_break:  # (payload array byte)
14175     0x11/imm32/alloc-id:fake:payload
14176     # "0f 83/jump-if-addr>= break/disp32"
14177     0x21/imm32/size
14178     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
14179 _string_0f_83_jump_loop:  # (payload array byte)
14180     0x11/imm32/alloc-id:fake:payload
14181     # "0f 83/jump-if-addr>= loop/disp32"
14182     0x20/imm32/size
14183     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
14184 _string_0f_84_jump_label:  # (payload array byte)
14185     0x11/imm32/alloc-id:fake:payload
14186     # "0f 84/jump-if-="
14187     0xf/imm32/size
14188     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/=
14189 _string_0f_84_jump_break:  # (payload array byte)
14190     0x11/imm32/alloc-id:fake:payload
14191     # "0f 84/jump-if-= break/disp32"
14192     0x1c/imm32/size
14193     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
14194 _string_0f_84_jump_loop:  # (payload array byte)
14195     0x11/imm32/alloc-id:fake:payload
14196     # "0f 84/jump-if-= loop/disp32"
14197     0x1b/imm32/size
14198     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
14199 _string_0f_85_jump_label:  # (payload array byte)
14200     0x11/imm32/alloc-id:fake:payload
14201     # "0f 85/jump-if-!="
14202     0x10/imm32/size
14203     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/=
14204 _string_0f_85_jump_break:  # (payload array byte)
14205     0x11/imm32/alloc-id:fake:payload
14206     # "0f 85/jump-if-!= break/disp32"
14207     0x1d/imm32/size
14208     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
14209 _string_0f_85_jump_loop:  # (payload array byte)
14210     0x11/imm32/alloc-id:fake:payload
14211     # "0f 85/jump-if-!= loop/disp32"
14212     0x1c/imm32/size
14213     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
14214 _string_0f_86_jump_label:  # (payload array byte)
14215     0x11/imm32/alloc-id:fake:payload
14216     # "0f 86/jump-if-addr<="
14217     0x14/imm32/size
14218     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/=
14219 _string_0f_86_jump_break:  # (payload array byte)
14220     0x11/imm32/alloc-id:fake:payload
14221     # "0f 86/jump-if-addr<= break/disp32"
14222     0x21/imm32/size
14223     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
14224 _string_0f_86_jump_loop:  # (payload array byte)
14225     0x11/imm32/alloc-id:fake:payload
14226     # "0f 86/jump-if-addr<= loop/disp32"
14227     0x20/imm32/size
14228     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
14229 _string_0f_87_jump_label:  # (payload array byte)
14230     0x11/imm32/alloc-id:fake:payload
14231     # "0f 87/jump-if-addr>"
14232     0x13/imm32/size
14233     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/>
14234 _string_0f_87_jump_break:  # (payload array byte)
14235     0x11/imm32/alloc-id:fake:payload
14236     # "0f 87/jump-if-addr> break/disp32"
14237     0x20/imm32/size
14238     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
14239 _string_0f_87_jump_loop:  # (payload array byte)
14240     0x11/imm32/alloc-id:fake:payload
14241     # "0f 87/jump-if-addr> loop/disp32"
14242     0x1f/imm32/size
14243     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
14244 _string_0f_8c_jump_label:  # (payload array byte)
14245     0x11/imm32/alloc-id:fake:payload
14246     # "0f 8c/jump-if-<"
14247     0xf/imm32/size
14248     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/<
14249 _string_0f_8c_jump_break:  # (payload array byte)
14250     0x11/imm32/alloc-id:fake:payload
14251     # "0f 8c/jump-if-< break/disp32"
14252     0x1c/imm32/size
14253     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
14254 _string_0f_8c_jump_loop:  # (payload array byte)
14255     0x11/imm32/alloc-id:fake:payload
14256     # "0f 8c/jump-if-< loop/disp32"
14257     0x1b/imm32/size
14258     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
14259 _string_0f_8d_jump_label:  # (payload array byte)
14260     0x11/imm32/alloc-id:fake:payload
14261     # "0f 8d/jump-if->="
14262     0x10/imm32/size
14263     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/=
14264 _string_0f_8d_jump_break:  # (payload array byte)
14265     0x11/imm32/alloc-id:fake:payload
14266     # "0f 8d/jump-if->= break/disp32"
14267     0x1d/imm32/size
14268     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
14269 _string_0f_8d_jump_loop:  # (payload array byte)
14270     0x11/imm32/alloc-id:fake:payload
14271     # "0f 8d/jump-if->= loop/disp32"
14272     0x1c/imm32/size
14273     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
14274 _string_0f_8e_jump_label:  # (payload array byte)
14275     0x11/imm32/alloc-id:fake:payload
14276     # "0f 8e/jump-if-<="
14277     0x10/imm32/size
14278     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/=
14279 _string_0f_8e_jump_break:  # (payload array byte)
14280     0x11/imm32/alloc-id:fake:payload
14281     # "0f 8e/jump-if-<= break/disp32"
14282     0x1d/imm32/size
14283     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
14284 _string_0f_8e_jump_loop:  # (payload array byte)
14285     0x11/imm32/alloc-id:fake:payload
14286     # "0f 8e/jump-if-<= loop/disp32"
14287     0x1c/imm32/size
14288     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
14289 _string_0f_8f_jump_label:  # (payload array byte)
14290     0x11/imm32/alloc-id:fake:payload
14291     # "0f 8f/jump-if->"
14292     0xf/imm32/size
14293     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/>
14294 _string_0f_8f_jump_break:  # (payload array byte)
14295     0x11/imm32/alloc-id:fake:payload
14296     # "0f 8f/jump-if-> break/disp32"
14297     0x1c/imm32/size
14298     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
14299 _string_0f_8f_jump_loop:  # (payload array byte)
14300     0x11/imm32/alloc-id:fake:payload
14301     # "0f 8f/jump-if-> loop/disp32"
14302     0x1b/imm32/size
14303     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
14304 _string_0f_af_multiply:  # (payload array byte)
14305     0x11/imm32/alloc-id:fake:payload
14306     # "0f af/multiply"
14307     0xe/imm32/size
14308     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
14309 _string_21_and_with:  # (payload array byte)
14310     0x11/imm32/alloc-id:fake:payload
14311     # "21/and-with"
14312     0xb/imm32/size
14313     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14314 _string_23_and:  # (payload array byte)
14315     0x11/imm32/alloc-id:fake:payload
14316     # "23/and"
14317     0x6/imm32/size
14318     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
14319 _string_25_and_with_eax:  # (payload array byte)
14320     0x11/imm32/alloc-id:fake:payload
14321     # "25/and-with-eax"
14322     0xf/imm32/size
14323     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
14324 _string_29_subtract_from:  # (payload array byte)
14325     0x11/imm32/alloc-id:fake:payload
14326     # "29/subtract-from"
14327     0x10/imm32/size
14328     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
14329 _string_2b_subtract:  # (payload array byte)
14330     0x11/imm32/alloc-id:fake:payload
14331     # "2b/subtract"
14332     0xb/imm32/size
14333     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
14334 _string_2d_subtract_from_eax:  # (payload array byte)
14335     0x11/imm32/alloc-id:fake:payload
14336     # "2d/subtract-from-eax"
14337     0x14/imm32/size
14338     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
14339 _string_31_xor_with:  # (payload array byte)
14340     0x11/imm32/alloc-id:fake:payload
14341     # "31/xor-with"
14342     0xb/imm32/size
14343     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
14344 _string_33_xor:  # (payload array byte)
14345     0x11/imm32/alloc-id:fake:payload
14346     # "33/xor"
14347     0x6/imm32/size
14348     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
14349 _string_35_xor_with_eax:  # (payload array byte)
14350     0x11/imm32/alloc-id:fake:payload
14351     # "35/xor-with-eax"
14352     0xf/imm32/size
14353     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
14354 _string_39_compare->:  # (payload array byte)
14355     0x11/imm32/alloc-id:fake:payload
14356     # "39/compare->"
14357     0xc/imm32/size
14358     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
14359 _string_3b_compare<-:  # (payload array byte)
14360     0x11/imm32/alloc-id:fake:payload
14361     # "3b/compare<-"
14362     0xc/imm32/size
14363     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
14364 _string_3d_compare_eax_with:  # (payload array byte)
14365     0x11/imm32/alloc-id:fake:payload
14366     # "3d/compare-eax-with"
14367     0x13/imm32/size
14368     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
14369 _string_40_increment_eax:  # (payload array byte)
14370     0x11/imm32/alloc-id:fake:payload
14371     # "40/increment-eax"
14372     0x10/imm32/size
14373     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
14374 _string_41_increment_ecx:  # (payload array byte)
14375     0x11/imm32/alloc-id:fake:payload
14376     # "41/increment-ecx"
14377     0x10/imm32/size
14378     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
14379 _string_42_increment_edx:  # (payload array byte)
14380     0x11/imm32/alloc-id:fake:payload
14381     # "42/increment-edx"
14382     0x10/imm32/size
14383     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
14384 _string_43_increment_ebx:  # (payload array byte)
14385     0x11/imm32/alloc-id:fake:payload
14386     # "43/increment-ebx"
14387     0x10/imm32/size
14388     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
14389 _string_46_increment_esi:  # (payload array byte)
14390     0x11/imm32/alloc-id:fake:payload
14391     # "46/increment-esi"
14392     0x10/imm32/size
14393     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
14394 _string_47_increment_edi:  # (payload array byte)
14395     0x11/imm32/alloc-id:fake:payload
14396     # "47/increment-edi"
14397     0x10/imm32/size
14398     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
14399 _string_48_decrement_eax:  # (payload array byte)
14400     0x11/imm32/alloc-id:fake:payload
14401     # "48/decrement-eax"
14402     0x10/imm32/size
14403     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
14404 _string_49_decrement_ecx:  # (payload array byte)
14405     0x11/imm32/alloc-id:fake:payload
14406     # "49/decrement-ecx"
14407     0x10/imm32/size
14408     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
14409 _string_4a_decrement_edx:  # (payload array byte)
14410     0x11/imm32/alloc-id:fake:payload
14411     # "4a/decrement-edx"
14412     0x10/imm32/size
14413     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
14414 _string_4b_decrement_ebx:  # (payload array byte)
14415     0x11/imm32/alloc-id:fake:payload
14416     # "4b/decrement-ebx"
14417     0x10/imm32/size
14418     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
14419 _string_4e_decrement_esi:  # (payload array byte)
14420     0x11/imm32/alloc-id:fake:payload
14421     # "4e/decrement-esi"
14422     0x10/imm32/size
14423     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
14424 _string_4f_decrement_edi:  # (payload array byte)
14425     0x11/imm32/alloc-id:fake:payload
14426     # "4f/decrement-edi"
14427     0x10/imm32/size
14428     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
14429 _string_81_subop_add:  # (payload array byte)
14430     0x11/imm32/alloc-id:fake:payload
14431     # "81 0/subop/add"
14432     0xe/imm32/size
14433     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
14434 _string_81_subop_or:  # (payload array byte)
14435     0x11/imm32/alloc-id:fake:payload
14436     # "81 1/subop/or"
14437     0xd/imm32/size
14438     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
14439 _string_81_subop_and:  # (payload array byte)
14440     0x11/imm32/alloc-id:fake:payload
14441     # "81 4/subop/and"
14442     0xe/imm32/size
14443     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
14444 _string_81_subop_subtract:  # (payload array byte)
14445     0x11/imm32/alloc-id:fake:payload
14446     # "81 5/subop/subtract"
14447     0x13/imm32/size
14448     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
14449 _string_81_subop_xor:  # (payload array byte)
14450     0x11/imm32/alloc-id:fake:payload
14451     # "81 6/subop/xor"
14452     0xe/imm32/size
14453     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
14454 _string_81_subop_compare:  # (payload array byte)
14455     0x11/imm32/alloc-id:fake:payload
14456     # "81 7/subop/compare"
14457     0x12/imm32/size
14458     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
14459 _string_89_<-:  # (payload array byte)
14460     0x11/imm32/alloc-id:fake:payload
14461     # "89/<-"
14462     0x5/imm32/size
14463     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
14464 _string_8b_->:  # (payload array byte)
14465     0x11/imm32/alloc-id:fake:payload
14466     # "8b/->"
14467     0x5/imm32/size
14468     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
14469 _string_8a_copy_byte:
14470     0x11/imm32/alloc-id:fake:payload
14471     # "8a/byte->"
14472     0x9/imm32/size
14473     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
14474 _string_88_copy_byte:
14475     0x11/imm32/alloc-id:fake:payload
14476     # "88/byte<-"
14477     0x9/imm32/size
14478     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
14479 _string_8d_copy_address:  # (payload array byte)
14480     0x11/imm32/alloc-id:fake:payload
14481     # "8d/copy-address"
14482     0xf/imm32/size
14483     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
14484 _string_b8_copy_to_eax:  # (payload array byte)
14485     0x11/imm32/alloc-id:fake:payload
14486     # "b8/copy-to-eax"
14487     0xe/imm32/size
14488     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
14489 _string_b9_copy_to_ecx:  # (payload array byte)
14490     0x11/imm32/alloc-id:fake:payload
14491     # "b9/copy-to-ecx"
14492     0xe/imm32/size
14493     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
14494 _string_ba_copy_to_edx:  # (payload array byte)
14495     0x11/imm32/alloc-id:fake:payload
14496     # "ba/copy-to-edx"
14497     0xe/imm32/size
14498     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
14499 _string_bb_copy_to_ebx:  # (payload array byte)
14500     0x11/imm32/alloc-id:fake:payload
14501     # "bb/copy-to-ebx"
14502     0xe/imm32/size
14503     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
14504 _string_be_copy_to_esi:  # (payload array byte)
14505     0x11/imm32/alloc-id:fake:payload
14506     # "be/copy-to-esi"
14507     0xe/imm32/size
14508     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
14509 _string_bf_copy_to_edi:  # (payload array byte)
14510     0x11/imm32/alloc-id:fake:payload
14511     # "bf/copy-to-edi"
14512     0xe/imm32/size
14513     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
14514 _string_c7_subop_copy:  # (payload array byte)
14515     0x11/imm32/alloc-id:fake:payload
14516     # "c7 0/subop/copy"
14517     0xf/imm32/size
14518     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
14519 _string_e9_jump_label:  # (payload array byte)
14520     0x11/imm32/alloc-id:fake:payload
14521     # "e9/jump"
14522     0x7/imm32/size
14523     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
14524 _string_e9_jump_break:  # (payload array byte)
14525     0x11/imm32/alloc-id:fake:payload
14526     # "e9/jump break/disp32"
14527     0x14/imm32/size
14528     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
14529 _string_e9_jump_loop:  # (payload array byte)
14530     0x11/imm32/alloc-id:fake:payload
14531     # "e9/jump loop/disp32"
14532     0x13/imm32/size
14533     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
14534 _string_ff_subop_increment:  # (payload array byte)
14535     0x11/imm32/alloc-id:fake:payload
14536     # "ff 0/subop/increment"
14537     0x14/imm32/size
14538     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
14539 _string_ff_subop_decrement:  # (payload array byte)
14540     0x11/imm32/alloc-id:fake:payload
14541     # "ff 1/subop/decrement"
14542     0x14/imm32/size
14543     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
14544 
14545 Single-int-var-in-mem:  # (payload list var)
14546     0x11/imm32/alloc-id:fake:payload
14547     0x11/imm32/alloc-id:fake
14548     Int-var-in-mem/imm32
14549     0/imm32/next
14550     0/imm32/next
14551 
14552 Int-var-in-mem:  # (payload var)
14553     0x11/imm32/alloc-id:fake:payload
14554     0/imm32/name
14555     0/imm32/name
14556     0x11/imm32/alloc-id:fake
14557     Type-int/imm32
14558     1/imm32/some-block-depth
14559     1/imm32/some-stack-offset
14560     0/imm32/no-register
14561     0/imm32/no-register
14562 
14563 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
14564 Single-byte-var-in-mem:  # (payload list var)
14565     0x11/imm32/alloc-id:fake:payload
14566     0x11/imm32/alloc-id:fake
14567     Byte-var-in-mem/imm32
14568     0/imm32/next
14569     0/imm32/next
14570 
14571 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
14572 Byte-var-in-mem:  # (payload var)
14573     0x11/imm32/alloc-id:fake:payload
14574     0/imm32/name
14575     0/imm32/name
14576     0x11/imm32/alloc-id:fake
14577     Type-byte/imm32
14578     1/imm32/some-block-depth
14579     1/imm32/some-stack-offset
14580     0/imm32/no-register
14581     0/imm32/no-register
14582 
14583 Two-args-int-stack-int-reg:  # (payload list var)
14584     0x11/imm32/alloc-id:fake:payload
14585     0x11/imm32/alloc-id:fake
14586     Int-var-in-mem/imm32
14587     0x11/imm32/alloc-id:fake
14588     Single-int-var-in-some-register/imm32/next
14589 
14590 Two-int-args-in-regs:  # (payload list var)
14591     0x11/imm32/alloc-id:fake:payload
14592     0x11/imm32/alloc-id:fake
14593     Int-var-in-some-register/imm32
14594     0x11/imm32/alloc-id:fake
14595     Single-int-var-in-some-register/imm32/next
14596 
14597 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
14598 Two-args-byte-stack-byte-reg:  # (payload list var)
14599     0x11/imm32/alloc-id:fake:payload
14600     0x11/imm32/alloc-id:fake
14601     Byte-var-in-mem/imm32
14602     0x11/imm32/alloc-id:fake
14603     Single-byte-var-in-some-register/imm32/next
14604 
14605 Two-args-int-reg-int-stack:  # (payload list var)
14606     0x11/imm32/alloc-id:fake:payload
14607     0x11/imm32/alloc-id:fake
14608     Int-var-in-some-register/imm32
14609     0x11/imm32/alloc-id:fake
14610     Single-int-var-in-mem/imm32/next
14611 
14612 Two-args-int-eax-int-literal:  # (payload list var)
14613     0x11/imm32/alloc-id:fake:payload
14614     0x11/imm32/alloc-id:fake
14615     Int-var-in-eax/imm32
14616     0x11/imm32/alloc-id:fake
14617     Single-lit-var/imm32/next
14618 
14619 Int-var-and-literal:  # (payload list var)
14620     0x11/imm32/alloc-id:fake:payload
14621     0x11/imm32/alloc-id:fake
14622     Int-var-in-mem/imm32
14623     0x11/imm32/alloc-id:fake
14624     Single-lit-var/imm32/next
14625 
14626 Int-var-in-register-and-literal:  # (payload list var)
14627     0x11/imm32/alloc-id:fake:payload
14628     0x11/imm32/alloc-id:fake
14629     Int-var-in-some-register/imm32
14630     0x11/imm32/alloc-id:fake
14631     Single-lit-var/imm32/next
14632 
14633 Single-int-var-in-some-register:  # (payload list var)
14634     0x11/imm32/alloc-id:fake:payload
14635     0x11/imm32/alloc-id:fake
14636     Int-var-in-some-register/imm32
14637     0/imm32/next
14638     0/imm32/next
14639 
14640 Single-addr-var-in-some-register:  # (payload list var)
14641     0x11/imm32/alloc-id:fake:payload
14642     0x11/imm32/alloc-id:fake
14643     Addr-var-in-some-register/imm32
14644     0/imm32/next
14645     0/imm32/next
14646 
14647 Single-byte-var-in-some-register:  # (payload list var)
14648     0x11/imm32/alloc-id:fake:payload
14649     0x11/imm32/alloc-id:fake
14650     Byte-var-in-some-register/imm32
14651     0/imm32/next
14652     0/imm32/next
14653 
14654 Int-var-in-some-register:  # (payload var)
14655     0x11/imm32/alloc-id:fake:payload
14656     0/imm32/name
14657     0/imm32/name
14658     0x11/imm32/alloc-id:fake
14659     Type-int/imm32
14660     1/imm32/some-block-depth
14661     0/imm32/no-stack-offset
14662     0x11/imm32/alloc-id:fake
14663     Any-register/imm32
14664 
14665 Any-register:  # (payload array byte)
14666     0x11/imm32/alloc-id:fake:payload
14667     1/imm32/size
14668     # data
14669     2a/asterisk
14670 
14671 Addr-var-in-some-register:  # (payload var)
14672     0x11/imm32/alloc-id:fake:payload
14673     0/imm32/name
14674     0/imm32/name
14675     0x11/imm32/alloc-id:fake
14676     Type-addr/imm32
14677     1/imm32/some-block-depth
14678     0/imm32/no-stack-offset
14679     0x11/imm32/alloc-id:fake
14680     Any-register/imm32
14681 
14682 Byte-var-in-some-register:  # (payload var)
14683     0x11/imm32/alloc-id:fake:payload
14684     0/imm32/name
14685     0/imm32/name
14686     0x11/imm32/alloc-id:fake
14687     Type-byte/imm32
14688     1/imm32/some-block-depth
14689     0/imm32/no-stack-offset
14690     0x11/imm32/alloc-id:fake
14691     Any-register/imm32
14692 
14693 Single-int-var-in-eax:  # (payload list var)
14694     0x11/imm32/alloc-id:fake:payload
14695     0x11/imm32/alloc-id:fake
14696     Int-var-in-eax/imm32
14697     0/imm32/next
14698     0/imm32/next
14699 
14700 Int-var-in-eax:
14701     0x11/imm32/alloc-id:fake:payload
14702     0/imm32/name
14703     0/imm32/name
14704     0x11/imm32/alloc-id:fake
14705     Type-int/imm32
14706     1/imm32/some-block-depth
14707     0/imm32/no-stack-offset
14708     0x11/imm32/alloc-id:fake
14709     $Register-eax/imm32
14710 
14711 Single-int-var-in-ecx:  # (payload list var)
14712     0x11/imm32/alloc-id:fake:payload
14713     0x11/imm32/alloc-id:fake
14714     Int-var-in-ecx/imm32
14715     0/imm32/next
14716     0/imm32/next
14717 
14718 Int-var-in-ecx:
14719     0x11/imm32/alloc-id:fake:payload
14720     0/imm32/name
14721     0/imm32/name
14722     0x11/imm32/alloc-id:fake
14723     Type-int/imm32
14724     1/imm32/some-block-depth
14725     0/imm32/no-stack-offset
14726     0x11/imm32/alloc-id:fake
14727     $Register-ecx/imm32/register
14728 
14729 Single-int-var-in-edx:  # (payload list var)
14730     0x11/imm32/alloc-id:fake:payload
14731     0x11/imm32/alloc-id:fake
14732     Int-var-in-edx/imm32
14733     0/imm32/next
14734     0/imm32/next
14735 
14736 Int-var-in-edx:  # (payload list var)
14737     0x11/imm32/alloc-id:fake:payload
14738     0/imm32/name
14739     0/imm32/name
14740     0x11/imm32/alloc-id:fake
14741     Type-int/imm32
14742     1/imm32/some-block-depth
14743     0/imm32/no-stack-offset
14744     0x11/imm32/alloc-id:fake
14745     $Register-edx/imm32/register
14746 
14747 Single-int-var-in-ebx:  # (payload list var)
14748     0x11/imm32/alloc-id:fake:payload
14749     0x11/imm32/alloc-id:fake
14750     Int-var-in-ebx/imm32
14751     0/imm32/next
14752     0/imm32/next
14753 
14754 Int-var-in-ebx:  # (payload list var)
14755     0x11/imm32/alloc-id:fake:payload
14756     0/imm32/name
14757     0/imm32/name
14758     0x11/imm32/alloc-id:fake
14759     Type-int/imm32
14760     1/imm32/some-block-depth
14761     0/imm32/no-stack-offset
14762     0x11/imm32/alloc-id:fake
14763     $Register-ebx/imm32/register
14764 
14765 Single-int-var-in-esi:  # (payload list var)
14766     0x11/imm32/alloc-id:fake:payload
14767     0x11/imm32/alloc-id:fake
14768     Int-var-in-esi/imm32
14769     0/imm32/next
14770     0/imm32/next
14771 
14772 Int-var-in-esi:  # (payload list var)
14773     0x11/imm32/alloc-id:fake:payload
14774     0/imm32/name
14775     0/imm32/name
14776     0x11/imm32/alloc-id:fake
14777     Type-int/imm32
14778     1/imm32/some-block-depth
14779     0/imm32/no-stack-offset
14780     0x11/imm32/alloc-id:fake
14781     $Register-esi/imm32/register
14782 
14783 Single-int-var-in-edi:  # (payload list var)
14784     0x11/imm32/alloc-id:fake:payload
14785     0x11/imm32/alloc-id:fake
14786     Int-var-in-edi/imm32
14787     0/imm32/next
14788     0/imm32/next
14789 
14790 Int-var-in-edi:  # (payload list var)
14791     0x11/imm32/alloc-id:fake:payload
14792     0/imm32/name
14793     0/imm32/name
14794     0x11/imm32/alloc-id:fake
14795     Type-int/imm32
14796     1/imm32/some-block-depth
14797     0/imm32/no-stack-offset
14798     0x11/imm32/alloc-id:fake
14799     $Register-edi/imm32/register
14800 
14801 Single-lit-var:  # (payload list var)
14802     0x11/imm32/alloc-id:fake:payload
14803     0x11/imm32/alloc-id:fake
14804     Lit-var/imm32
14805     0/imm32/next
14806     0/imm32/next
14807 
14808 Lit-var:  # (payload var)
14809     0x11/imm32/alloc-id:fake:payload
14810     0/imm32/name
14811     0/imm32/name
14812     0x11/imm32/alloc-id:fake
14813     Type-literal/imm32
14814     1/imm32/some-block-depth
14815     0/imm32/no-stack-offset
14816     0/imm32/no-register
14817     0/imm32/no-register
14818 
14819 Type-int:  # (payload tree type-id)
14820     0x11/imm32/alloc-id:fake:payload
14821     1/imm32/left-is-atom
14822     1/imm32/value:int
14823     0/imm32/left:unused
14824     0/imm32/right:null
14825     0/imm32/right:null
14826 
14827 Type-literal:  # (payload tree type-id)
14828     0x11/imm32/alloc-id:fake:payload
14829     1/imm32/is-atom
14830     0/imm32/value:literal
14831     0/imm32/left:unused
14832     0/imm32/right:null
14833     0/imm32/right:null
14834 
14835 Type-addr:  # (payload tree type-id)
14836     0x11/imm32/alloc-id:fake:payload
14837     1/imm32/is-atom
14838     2/imm32/value:addr
14839     0/imm32/left:unused
14840     0/imm32/right:null
14841     0/imm32/right:null
14842 
14843 Type-byte:  # (payload tree type-id)
14844     0x11/imm32/alloc-id:fake:payload
14845     1/imm32/is-atom
14846     8/imm32/value:byte
14847     0/imm32/left:unused
14848     0/imm32/right:null
14849     0/imm32/right:null
14850 
14851 == code
14852 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
14853     # . prologue
14854     55/push-ebp
14855     89/<- %ebp 4/r32/esp
14856     # . save registers
14857     50/push-eax
14858     51/push-ecx
14859     # ecx = primitive
14860     8b/-> *(ebp+0x10) 1/r32/ecx
14861     # emit primitive name
14862     (emit-indent *(ebp+8) *Curr-block-depth)
14863     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
14864     (write-buffered *(ebp+8) %eax)
14865     # emit rm32 if necessary
14866     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
14867     # emit r32 if necessary
14868     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
14869     # emit imm32 if necessary
14870     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
14871     # emit disp32 if necessary
14872     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
14873     (write-buffered *(ebp+8) Newline)
14874 $emit-subx-primitive:end:
14875     # . restore registers
14876     59/pop-to-ecx
14877     58/pop-to-eax
14878     # . epilogue
14879     89/<- %esp 5/r32/ebp
14880     5d/pop-to-ebp
14881     c3/return
14882 
14883 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14884     # . prologue
14885     55/push-ebp
14886     89/<- %ebp 4/r32/esp
14887     # . save registers
14888     50/push-eax
14889     # if (l == 0) return
14890     81 7/subop/compare *(ebp+0xc) 0/imm32
14891     74/jump-if-= $emit-subx-rm32:end/disp8
14892     # var v/eax: (addr stmt-var)
14893     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
14894     (emit-subx-var-as-rm32 *(ebp+8) %eax)
14895 $emit-subx-rm32:end:
14896     # . restore registers
14897     58/pop-to-eax
14898     # . epilogue
14899     89/<- %esp 5/r32/ebp
14900     5d/pop-to-ebp
14901     c3/return
14902 
14903 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)
14904     # . prologue
14905     55/push-ebp
14906     89/<- %ebp 4/r32/esp
14907     # . save registers
14908     51/push-ecx
14909     # eax = l
14910     8b/-> *(ebp+0xc) 0/r32/eax
14911     # ecx = stmt
14912     8b/-> *(ebp+8) 1/r32/ecx
14913     # if (l == 1) return stmt->inouts
14914     {
14915       3d/compare-eax-and 1/imm32
14916       75/jump-if-!= break/disp8
14917 $get-stmt-operand-from-arg-location:1:
14918       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14919       eb/jump $get-stmt-operand-from-arg-location:end/disp8
14920     }
14921     # if (l == 2) return stmt->inouts->next
14922     {
14923       3d/compare-eax-and 2/imm32
14924       75/jump-if-!= break/disp8
14925 $get-stmt-operand-from-arg-location:2:
14926       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14927       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14928       eb/jump $get-stmt-operand-from-arg-location:end/disp8
14929     }
14930     # if (l == 3) return stmt->outputs
14931     {
14932       3d/compare-eax-and 3/imm32
14933       75/jump-if-!= break/disp8
14934 $get-stmt-operand-from-arg-location:3:
14935       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14936       eb/jump $get-stmt-operand-from-arg-location:end/disp8
14937     }
14938     # abort
14939     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
14940 $get-stmt-operand-from-arg-location:end:
14941     # . restore registers
14942     59/pop-to-ecx
14943     # . epilogue
14944     89/<- %esp 5/r32/ebp
14945     5d/pop-to-ebp
14946     c3/return
14947 
14948 $get-stmt-operand-from-arg-location:abort:
14949     # error("invalid arg-location " eax)
14950     (write-buffered *(ebp+0x10) "invalid arg-location ")
14951     (print-int32-buffered *(ebp+0x10) %eax)
14952     (write-buffered *(ebp+0x10) Newline)
14953     (flush *(ebp+0x10))
14954     (stop *(ebp+0x14) 1)
14955     # never gets here
14956 
14957 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
14958     # . prologue
14959     55/push-ebp
14960     89/<- %ebp 4/r32/esp
14961     # . save registers
14962     50/push-eax
14963     51/push-ecx
14964     # if (l == 0) return
14965     81 7/subop/compare *(ebp+0xc) 0/imm32
14966     0f 84/jump-if-= $emit-subx-r32:end/disp32
14967     # var v/eax: (addr stmt-var)
14968     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
14969     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14970     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14971     (maybe-get Registers %eax 0xc)  # => eax: (addr register-index)
14972     (write-buffered *(ebp+8) Space)
14973     (print-int32-buffered *(ebp+8) *eax)
14974     (write-buffered *(ebp+8) "/r32")
14975 $emit-subx-r32:end:
14976     # . restore registers
14977     59/pop-to-ecx
14978     58/pop-to-eax
14979     # . epilogue
14980     89/<- %esp 5/r32/ebp
14981     5d/pop-to-ebp
14982     c3/return
14983 
14984 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
14985     # . prologue
14986     55/push-ebp
14987     89/<- %ebp 4/r32/esp
14988     # . save registers
14989     50/push-eax
14990     51/push-ecx
14991     # if (l == 0) return
14992     81 7/subop/compare *(ebp+0xc) 0/imm32
14993     0f 84/jump-if-= $emit-subx-imm32:end/disp32
14994     # var v/eax: (handle var)
14995     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
14996     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14997     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14998     (write-buffered *(ebp+8) Space)
14999     (write-buffered *(ebp+8) %eax)
15000     (write-buffered *(ebp+8) "/imm32")
15001 $emit-subx-imm32:end:
15002     # . restore registers
15003     59/pop-to-ecx
15004     58/pop-to-eax
15005     # . epilogue
15006     89/<- %esp 5/r32/ebp
15007     5d/pop-to-ebp
15008     c3/return
15009 
15010 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
15011     # . prologue
15012     55/push-ebp
15013     89/<- %ebp 4/r32/esp
15014     # . save registers
15015     50/push-eax
15016     51/push-ecx
15017     # if (location == 0) return
15018     81 7/subop/compare *(ebp+0xc) 0/imm32
15019     0f 84/jump-if-= $emit-subx-disp32:end/disp32
15020     # var v/eax: (addr stmt-var)
15021     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
15022     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
15023     (lookup *eax *(eax+4))  # Var-name Var-name => eax
15024     (write-buffered *(ebp+8) Space)
15025     (write-buffered *(ebp+8) %eax)
15026     # hack: if instruction operation starts with "break", emit ":break"
15027     # var name/ecx: (addr array byte) = lookup(stmt->operation)
15028     8b/-> *(ebp+0x10) 0/r32/eax
15029     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15030     89/<- %ecx 0/r32/eax
15031     {
15032       (string-starts-with? %ecx "break")  # => eax
15033       3d/compare-eax-and 0/imm32/false
15034       74/jump-if-= break/disp8
15035       (write-buffered *(ebp+8) ":break")
15036     }
15037     # hack: if instruction operation starts with "loop", emit ":loop"
15038     {
15039       (string-starts-with? %ecx "loop")  # => eax
15040       3d/compare-eax-and 0/imm32/false
15041       74/jump-if-= break/disp8
15042       (write-buffered *(ebp+8) ":loop")
15043     }
15044     (write-buffered *(ebp+8) "/disp32")
15045 $emit-subx-disp32:end:
15046     # . restore registers
15047     59/pop-to-ecx
15048     58/pop-to-eax
15049     # . epilogue
15050     89/<- %esp 5/r32/ebp
15051     5d/pop-to-ebp
15052     c3/return
15053 
15054 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
15055     # . prologue
15056     55/push-ebp
15057     89/<- %ebp 4/r32/esp
15058     # . save registers
15059     50/push-eax
15060     51/push-ecx
15061     #
15062     (emit-indent *(ebp+8) *Curr-block-depth)
15063     (write-buffered *(ebp+8) "(")
15064     # ecx = stmt
15065     8b/-> *(ebp+0xc) 1/r32/ecx
15066     # - emit function name
15067     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15068     (write-buffered *(ebp+8) %eax)
15069     # - emit arguments
15070     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
15071     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15072     {
15073       # if (curr == null) break
15074       3d/compare-eax-and 0/imm32
15075       74/jump-if-= break/disp8
15076       #
15077       (emit-subx-call-operand *(ebp+8) %eax)
15078       # curr = lookup(curr->next)
15079       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
15080       eb/jump loop/disp8
15081     }
15082     #
15083     (write-buffered *(ebp+8) ")\n")
15084 $emit-call:end:
15085     # . restore registers
15086     59/pop-to-ecx
15087     58/pop-to-eax
15088     # . epilogue
15089     89/<- %esp 5/r32/ebp
15090     5d/pop-to-ebp
15091     c3/return
15092 
15093 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
15094     # shares code with emit-subx-var-as-rm32
15095     # . prologue
15096     55/push-ebp
15097     89/<- %ebp 4/r32/esp
15098     # . save registers
15099     50/push-eax
15100     51/push-ecx
15101     56/push-esi
15102     # ecx = s
15103     8b/-> *(ebp+0xc) 1/r32/ecx
15104     # var operand/esi: (addr var) = lookup(s->value)
15105     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15106     89/<- %esi 0/r32/eax
15107     # if (operand->register && !s->is-deref?) emit "%__"
15108     {
15109 $emit-subx-call-operand:check-for-register-direct:
15110       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15111       74/jump-if-= break/disp8
15112       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15113       75/jump-if-!= break/disp8
15114 $emit-subx-call-operand:register-direct:
15115       (write-buffered *(ebp+8) " %")
15116       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15117       (write-buffered *(ebp+8) %eax)
15118       e9/jump $emit-subx-call-operand:end/disp32
15119     }
15120     # else if (operand->register && s->is-deref?) emit "*__"
15121     {
15122 $emit-subx-call-operand:check-for-register-indirect:
15123       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15124       74/jump-if-= break/disp8
15125       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15126       74/jump-if-= break/disp8
15127 $emit-subx-call-operand:register-indirect:
15128       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
15129       e9/jump $emit-subx-call-operand:end/disp32
15130     }
15131     # else if (operand->stack-offset) emit "*(ebp+__)"
15132     {
15133       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
15134       74/jump-if-= break/disp8
15135 $emit-subx-call-operand:stack:
15136       (emit-subx-call-operand-stack *(ebp+8) %esi)
15137       e9/jump $emit-subx-call-operand:end/disp32
15138     }
15139     # else if (operand->type == literal) emit "__"
15140     {
15141       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
15142       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
15143       75/jump-if-!= break/disp8
15144 $emit-subx-call-operand:literal:
15145       (write-buffered *(ebp+8) Space)
15146       (lookup *esi *(esi+4))  # Var-name Var-name => eax
15147       (write-buffered *(ebp+8) %eax)
15148     }
15149 $emit-subx-call-operand:end:
15150     # . restore registers
15151     5e/pop-to-esi
15152     59/pop-to-ecx
15153     58/pop-to-eax
15154     # . epilogue
15155     89/<- %esp 5/r32/ebp
15156     5d/pop-to-ebp
15157     c3/return
15158 
15159 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
15160     # . prologue
15161     55/push-ebp
15162     89/<- %ebp 4/r32/esp
15163     # . save registers
15164     50/push-eax
15165     51/push-ecx
15166     56/push-esi
15167     # esi = v
15168     8b/-> *(ebp+0xc) 6/r32/esi
15169     # var size/ecx: int = size-of-deref(v)
15170     (size-of-deref %esi)  # => eax
15171     89/<- %ecx 0/r32/eax
15172     # var reg-name/esi: (addr array byte) = lookup(v->register)
15173     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15174     89/<- %esi 0/r32/eax
15175     # TODO: assert size is a multiple of 4
15176     # var i/eax: int = 0
15177     b8/copy-to-eax 0/imm32
15178     {
15179 $emit-subx-call-operand-register-indirect:loop:
15180       # if (i >= size) break
15181       39/compare %eax 1/r32/ecx
15182       7d/jump-if->= break/disp8
15183       # emit " *(" v->register "+" i ")"
15184       (write-buffered *(ebp+8) " *(")
15185       (write-buffered *(ebp+8) %esi)
15186       (write-buffered *(ebp+8) "+")
15187       (print-int32-buffered *(ebp+8) %eax)
15188       (write-buffered *(ebp+8) ")")
15189       # i += 4
15190       05/add-to-eax 4/imm32
15191       #
15192       eb/jump loop/disp8
15193     }
15194 $emit-subx-call-operand-register-indirect:end:
15195     # . restore registers
15196     5e/pop-to-esi
15197     59/pop-to-ecx
15198     58/pop-to-eax
15199     # . epilogue
15200     89/<- %esp 5/r32/ebp
15201     5d/pop-to-ebp
15202     c3/return
15203 
15204 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
15205     # . prologue
15206     55/push-ebp
15207     89/<- %ebp 4/r32/esp
15208     # . save registers
15209     50/push-eax
15210     51/push-ecx
15211     56/push-esi
15212     # esi = v
15213     8b/-> *(ebp+0xc) 6/r32/esi
15214     # var curr/ecx: int = v->offset
15215     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
15216     # var max/eax: int = v->offset + size-of(v)
15217     (size-of %esi)  # => eax
15218     # TODO: assert size is a multiple of 4
15219     01/add-to %eax 1/r32/ecx
15220     {
15221 $emit-subx-call-operand-stack:loop:
15222       # if (curr >= max) break
15223       39/compare %ecx 0/r32/eax
15224       7d/jump-if->= break/disp8
15225       # emit " *(ebp+" curr ")"
15226       (write-buffered *(ebp+8) " *(ebp+")
15227       (print-int32-buffered *(ebp+8) %ecx)
15228       (write-buffered *(ebp+8) ")")
15229       # i += 4
15230       81 0/subop/add %ecx 4/imm32
15231       #
15232       eb/jump loop/disp8
15233     }
15234 $emit-subx-call-operand-stack:end:
15235     # . restore registers
15236     5e/pop-to-esi
15237     59/pop-to-ecx
15238     58/pop-to-eax
15239     # . epilogue
15240     89/<- %esp 5/r32/ebp
15241     5d/pop-to-ebp
15242     c3/return
15243 
15244 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
15245     # . prologue
15246     55/push-ebp
15247     89/<- %ebp 4/r32/esp
15248     # . save registers
15249     50/push-eax
15250     51/push-ecx
15251     56/push-esi
15252     # ecx = s
15253     8b/-> *(ebp+0xc) 1/r32/ecx
15254     # var operand/esi: (addr var) = lookup(s->value)
15255     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15256     89/<- %esi 0/r32/eax
15257     # if (operand->register && s->is-deref?) emit "*__"
15258     {
15259 $emit-subx-var-as-rm32:check-for-register-indirect:
15260       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15261       74/jump-if-= break/disp8
15262       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15263       74/jump-if-= break/disp8
15264 $emit-subx-var-as-rm32:register-indirect:
15265       (write-buffered *(ebp+8) " *")
15266       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15267       (write-buffered *(ebp+8) %eax)
15268       e9/jump $emit-subx-var-as-rm32:end/disp32
15269     }
15270     # if (operand->register && !s->is-deref?) emit "%__"
15271     {
15272 $emit-subx-var-as-rm32:check-for-register-direct:
15273       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15274       74/jump-if-= break/disp8
15275       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15276       75/jump-if-!= break/disp8
15277 $emit-subx-var-as-rm32:register-direct:
15278       (write-buffered *(ebp+8) " %")
15279       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15280       (write-buffered *(ebp+8) %eax)
15281       e9/jump $emit-subx-var-as-rm32:end/disp32
15282     }
15283     # else if (operand->stack-offset) emit "*(ebp+__)"
15284     {
15285       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
15286       74/jump-if-= break/disp8
15287 $emit-subx-var-as-rm32:stack:
15288       (write-buffered *(ebp+8) Space)
15289       (write-buffered *(ebp+8) "*(ebp+")
15290       (print-int32-buffered *(ebp+8) *(esi+0x14))  # Var-offset
15291       (write-buffered *(ebp+8) ")")
15292     }
15293 $emit-subx-var-as-rm32:end:
15294     # . restore registers
15295     5e/pop-to-esi
15296     59/pop-to-ecx
15297     58/pop-to-eax
15298     # . epilogue
15299     89/<- %esp 5/r32/ebp
15300     5d/pop-to-ebp
15301     c3/return
15302 
15303 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
15304     # . prologue
15305     55/push-ebp
15306     89/<- %ebp 4/r32/esp
15307     # . save registers
15308     51/push-ecx
15309     # var curr/ecx: (addr primitive) = primitives
15310     8b/-> *(ebp+8) 1/r32/ecx
15311     {
15312 $find-matching-primitive:loop:
15313       # if (curr == null) break
15314       81 7/subop/compare %ecx 0/imm32
15315       74/jump-if-= break/disp8
15316       # if match(curr, stmt) return curr
15317       {
15318         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
15319         3d/compare-eax-and 0/imm32/false
15320         74/jump-if-= break/disp8
15321         89/<- %eax 1/r32/ecx
15322         eb/jump $find-matching-primitive:end/disp8
15323       }
15324 $find-matching-primitive:next-primitive:
15325       # curr = curr->next
15326       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
15327       89/<- %ecx 0/r32/eax
15328       #
15329       e9/jump loop/disp32
15330     }
15331     # return null
15332     b8/copy-to-eax 0/imm32
15333 $find-matching-primitive:end:
15334     # . restore registers
15335     59/pop-to-ecx
15336     # . epilogue
15337     89/<- %esp 5/r32/ebp
15338     5d/pop-to-ebp
15339     c3/return
15340 
15341 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
15342     # A mu stmt matches a primitive if the name matches, all the inout vars
15343     # match, and all the output vars match.
15344     # Vars match if types match and registers match.
15345     # In addition, a stmt output matches a primitive's output if types match
15346     # and the primitive has a wildcard register.
15347     # . prologue
15348     55/push-ebp
15349     89/<- %ebp 4/r32/esp
15350     # . save registers
15351     51/push-ecx
15352     52/push-edx
15353     53/push-ebx
15354     56/push-esi
15355     57/push-edi
15356     # ecx = stmt
15357     8b/-> *(ebp+8) 1/r32/ecx
15358     # edx = primitive
15359     8b/-> *(ebp+0xc) 2/r32/edx
15360     {
15361 $mu-stmt-matches-primitive?:check-name:
15362       # if (primitive->name != stmt->operation) return false
15363       # . var esi: (addr array byte) = lookup(stmt->operation)
15364       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
15365       89/<- %esi 0/r32/eax
15366       # . var edi: (addr array byte) = lookup(primitive->name)
15367       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
15368       89/<- %edi 0/r32/eax
15369       (string-equal? %esi %edi)  # => eax
15370       3d/compare-eax-and 0/imm32/false
15371       75/jump-if-!= break/disp8
15372       b8/copy-to-eax 0/imm32
15373       e9/jump $mu-stmt-matches-primitive?:end/disp32
15374     }
15375     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
15376     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
15377     89/<- %esi 0/r32/eax
15378     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
15379     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
15380     89/<- %edi 0/r32/eax
15381     {
15382 $mu-stmt-matches-primitive?:inouts-loop:
15383       # if (curr == 0 && curr2 == 0) move on to check outputs
15384       {
15385 $mu-stmt-matches-primitive?:check-both-inouts-null:
15386         81 7/subop/compare %esi 0/imm32
15387         75/jump-if-!= break/disp8
15388 $mu-stmt-matches-primitive?:stmt-inout-null:
15389         81 7/subop/compare %edi 0/imm32
15390         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
15391 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
15392         # return false
15393         b8/copy-to-eax 0/imm32/false
15394         e9/jump $mu-stmt-matches-primitive?:end/disp32
15395       }
15396       # if (curr2 == 0) return false
15397       {
15398 $mu-stmt-matches-primitive?:check-prim-inout-null:
15399         81 7/subop/compare %edi 0/imm32
15400         75/jump-if-!= break/disp8
15401 $mu-stmt-matches-primitive?:prim-inout-null:
15402         b8/copy-to-eax 0/imm32/false
15403         e9/jump $mu-stmt-matches-primitive?:end/disp32
15404       }
15405       # if (curr != curr2) return false
15406       {
15407 $mu-stmt-matches-primitive?:check-inouts-match:
15408         (lookup *edi *(edi+4))  # List-value List-value => eax
15409         (operand-matches-primitive? %esi %eax)  # => eax
15410         3d/compare-eax-and 0/imm32/false
15411         75/jump-if-!= break/disp8
15412 $mu-stmt-matches-primitive?:inouts-match:
15413         b8/copy-to-eax 0/imm32/false
15414         e9/jump $mu-stmt-matches-primitive?:end/disp32
15415       }
15416 $mu-stmt-matches-primitive?:next-inout:
15417       # curr = lookup(curr->next)
15418       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
15419       89/<- %esi 0/r32/eax
15420       # curr2 = lookup(curr2->next)
15421       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
15422       89/<- %edi 0/r32/eax
15423       #
15424       e9/jump loop/disp32
15425     }
15426 $mu-stmt-matches-primitive?:check-outputs:
15427     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
15428     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
15429     89/<- %esi 0/r32/eax
15430     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
15431     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
15432     89/<- %edi 0/r32/eax
15433     {
15434 $mu-stmt-matches-primitive?:outputs-loop:
15435       # if (curr == 0) return (curr2 == 0)
15436       {
15437 $mu-stmt-matches-primitive?:check-both-outputs-null:
15438         81 7/subop/compare %esi 0/imm32
15439         75/jump-if-!= break/disp8
15440         {
15441 $mu-stmt-matches-primitive?:stmt-output-null:
15442           81 7/subop/compare %edi 0/imm32
15443           75/jump-if-!= break/disp8
15444 $mu-stmt-matches-primitive?:both-outputs-null:
15445           # return true
15446           b8/copy-to-eax 1/imm32
15447           e9/jump $mu-stmt-matches-primitive?:end/disp32
15448         }
15449 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
15450         # return false
15451         b8/copy-to-eax 0/imm32
15452         e9/jump $mu-stmt-matches-primitive?:end/disp32
15453       }
15454       # if (curr2 == 0) return false
15455       {
15456 $mu-stmt-matches-primitive?:check-prim-output-null:
15457         81 7/subop/compare %edi 0/imm32
15458         75/jump-if-!= break/disp8
15459 $mu-stmt-matches-primitive?:prim-output-is-null:
15460         b8/copy-to-eax 0/imm32
15461         e9/jump $mu-stmt-matches-primitive?:end/disp32
15462       }
15463       # if (curr != curr2) return false
15464       {
15465 $mu-stmt-matches-primitive?:check-outputs-match:
15466         (lookup *edi *(edi+4))  # List-value List-value => eax
15467         (operand-matches-primitive? %esi %eax)  # => eax
15468         3d/compare-eax-and 0/imm32/false
15469         75/jump-if-!= break/disp8
15470 $mu-stmt-matches-primitive?:outputs-match:
15471         b8/copy-to-eax 0/imm32
15472         e9/jump $mu-stmt-matches-primitive?:end/disp32
15473       }
15474 $mu-stmt-matches-primitive?:next-output:
15475       # curr = lookup(curr->next)
15476       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
15477       89/<- %esi 0/r32/eax
15478       # curr2 = lookup(curr2->next)
15479       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
15480       89/<- %edi 0/r32/eax
15481       #
15482       e9/jump loop/disp32
15483     }
15484 $mu-stmt-matches-primitive?:return-true:
15485     b8/copy-to-eax 1/imm32
15486 $mu-stmt-matches-primitive?:end:
15487     # . restore registers
15488     5f/pop-to-edi
15489     5e/pop-to-esi
15490     5b/pop-to-ebx
15491     5a/pop-to-edx
15492     59/pop-to-ecx
15493     # . epilogue
15494     89/<- %esp 5/r32/ebp
15495     5d/pop-to-ebp
15496     c3/return
15497 
15498 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
15499     # . prologue
15500     55/push-ebp
15501     89/<- %ebp 4/r32/esp
15502     # . save registers
15503     51/push-ecx
15504     52/push-edx
15505     53/push-ebx
15506     56/push-esi
15507     57/push-edi
15508     # ecx = s
15509     8b/-> *(ebp+8) 1/r32/ecx
15510     # var var/esi: (addr var) = lookup(s->value)
15511     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
15512     89/<- %esi 0/r32/eax
15513     # edi = prim-var
15514     8b/-> *(ebp+0xc) 7/r32/edi
15515 $operand-matches-primitive?:check-type:
15516     # if (var->type != prim-var->type) return false
15517     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
15518     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
15519     89/<- %ebx 0/r32/eax
15520     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
15521     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
15522     (subx-type-equal? %ebx %eax)  # => eax
15523     3d/compare-eax-and 0/imm32/false
15524     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
15525     {
15526 $operand-matches-primitive?:check-register:
15527       # if prim-var is in memory and var is in register but dereference, match
15528       {
15529         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
15530         0f 85/jump-if-!= break/disp32
15531         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15532         74/jump-if-= break/disp8
15533         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15534         74/jump-if-= break/disp8
15535 $operand-matches-primitive?:var-deref-match:
15536         e9/jump $operand-matches-primitive?:return-true/disp32
15537       }
15538       # if prim-var is in register and var is in register but dereference, no match
15539       {
15540         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
15541         0f 84/jump-if-= break/disp32
15542         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
15543         0f 84/jump-if-= break/disp32
15544         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
15545         74/jump-if-= break/disp8
15546 $operand-matches-primitive?:var-deref-no-match:
15547         e9/jump $operand-matches-primitive?:return-false/disp32
15548       }
15549       # return false if var->register doesn't match prim-var->register
15550       {
15551         # if register addresses are equal, it's a match
15552         # var vreg/ebx: (addr array byte) = lookup(var->register)
15553         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
15554         89/<- %ebx 0/r32/eax
15555         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
15556         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
15557         89/<- %ecx 0/r32/eax
15558         # if (vreg == preg) break
15559         39/compare %ecx 3/r32/ebx
15560         74/jump-if-= break/disp8
15561 $operand-matches-primitive?:var-register-no-match:
15562         # if either address is 0, return false
15563         81 7/subop/compare %ebx 0/imm32
15564         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
15565         81 7/subop/compare %ecx 0/imm32
15566         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
15567         # if prim-var->register is wildcard, it's a match
15568         (string-equal? %ecx "*")  # Any-register => eax
15569         3d/compare-eax-and 0/imm32/false
15570         75/jump-if-!= break/disp8
15571 $operand-matches-primitive?:wildcard-no-match:
15572         # if string contents aren't equal, return false
15573         (string-equal? %ecx %ebx)  # => eax
15574         3d/compare-eax-and 0/imm32/false
15575         74/jump-if-= $operand-matches-primitive?:return-false/disp8
15576       }
15577     }
15578 $operand-matches-primitive?:return-true:
15579     b8/copy-to-eax 1/imm32/true
15580     eb/jump $operand-matches-primitive?:end/disp8
15581 $operand-matches-primitive?:return-false:
15582     b8/copy-to-eax 0/imm32/false
15583 $operand-matches-primitive?:end:
15584     # . restore registers
15585     5f/pop-to-edi
15586     5e/pop-to-esi
15587     5b/pop-to-ebx
15588     5a/pop-to-edx
15589     59/pop-to-ecx
15590     # . epilogue
15591     89/<- %esp 5/r32/ebp
15592     5d/pop-to-ebp
15593     c3/return
15594 
15595 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
15596     # . prologue
15597     55/push-ebp
15598     89/<- %ebp 4/r32/esp
15599     # . save registers
15600     51/push-ecx
15601     # var curr/ecx: (handle function) = functions
15602     8b/-> *(ebp+8) 1/r32/ecx
15603     {
15604       # if (curr == null) break
15605       81 7/subop/compare %ecx 0/imm32
15606       74/jump-if-= break/disp8
15607 #?       (write-buffered Stderr "iter\n")
15608 #?       (flush Stderr)
15609       # if match(stmt, curr) return curr
15610       {
15611         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
15612         3d/compare-eax-and 0/imm32/false
15613         74/jump-if-= break/disp8
15614         89/<- %eax 1/r32/ecx
15615         eb/jump $find-matching-function:end/disp8
15616       }
15617       # curr = curr->next
15618       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
15619       89/<- %ecx 0/r32/eax
15620       #
15621       eb/jump loop/disp8
15622     }
15623     # return null
15624     b8/copy-to-eax 0/imm32
15625 $find-matching-function:end:
15626     # . restore registers
15627     59/pop-to-ecx
15628     # . epilogue
15629     89/<- %esp 5/r32/ebp
15630     5d/pop-to-ebp
15631     c3/return
15632 
15633 # Just compare names; user-defined functions don't support overloading yet.
15634 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
15635     # . prologue
15636     55/push-ebp
15637     89/<- %ebp 4/r32/esp
15638     # . save registers
15639     51/push-ecx
15640     # return function->name == stmt->operation
15641     # ecx = lookup(stmt->operation)
15642     8b/-> *(ebp+8) 0/r32/eax
15643     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
15644     89/<- %ecx 0/r32/eax
15645     # eax = lookup(function->name)
15646     8b/-> *(ebp+0xc) 0/r32/eax
15647     (lookup *eax *(eax+4))  # Function-name Function-name => eax
15648     (string-equal? %eax %ecx)  # => eax
15649 $mu-stmt-matches-function?:end:
15650     # . restore registers
15651     59/pop-to-ecx
15652     # . epilogue
15653     89/<- %esp 5/r32/ebp
15654     5d/pop-to-ebp
15655     c3/return
15656 
15657 subx-type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
15658     # . prologue
15659     55/push-ebp
15660     89/<- %ebp 4/r32/esp
15661     # . save registers
15662     51/push-ecx
15663     # var alit/ecx: boolean = is-literal-type?(a)
15664     (is-simple-mu-type? *(ebp+8) 0)  # => eax
15665     89/<- %ecx 0/r32/eax
15666     # var blit/eax: boolean = is-literal-type?(b)
15667     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
15668     # return alit == blit
15669     39/compare %eax 1/r32/ecx
15670     0f 94/set-byte-if-= %al
15671     81 4/subop/and %eax 0xff/imm32
15672 $subx-type-equal?:end:
15673     # . restore registers
15674     59/pop-to-ecx
15675     # . epilogue
15676     89/<- %esp 5/r32/ebp
15677     5d/pop-to-ebp
15678     c3/return
15679 
15680 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
15681     # . prologue
15682     55/push-ebp
15683     89/<- %ebp 4/r32/esp
15684     # . save registers
15685     51/push-ecx
15686     # ecx = n
15687     8b/-> *(ebp+0xc) 1/r32/ecx
15688     # return (a->value == n)
15689     8b/-> *(ebp+8) 0/r32/eax
15690     39/compare *(eax+4) 1/r32/ecx  # Tree-value
15691     0f 94/set-byte-if-= %al
15692     81 4/subop/and %eax 0xff/imm32
15693 $is-simple-mu-type?:end:
15694     # . restore registers
15695     59/pop-to-ecx
15696     # . epilogue
15697     89/<- %esp 5/r32/ebp
15698     5d/pop-to-ebp
15699     c3/return
15700 
15701 test-emit-subx-stmt-primitive:
15702     # Primitive operation on a variable on the stack.
15703     #   increment foo
15704     # =>
15705     #   ff 0/subop/increment *(ebp-8)
15706     #
15707     # There's a variable on the var stack as follows:
15708     #   name: 'foo'
15709     #   type: int
15710     #   stack-offset: -8
15711     #
15712     # There's a primitive with this info:
15713     #   name: 'increment'
15714     #   inouts: int/mem
15715     #   value: 'ff 0/subop/increment'
15716     #
15717     # . prologue
15718     55/push-ebp
15719     89/<- %ebp 4/r32/esp
15720     # setup
15721     (clear-stream _test-output-stream)
15722     (clear-stream $_test-output-buffered-file->buffer)
15723     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
15724 $test-emit-subx-stmt-primitive:initialize-type:
15725     # var type/ecx: (payload tree type-id) = int
15726     68/push 0/imm32/right:null
15727     68/push 0/imm32/right:null
15728     68/push 0/imm32/left:unused
15729     68/push 1/imm32/value:int
15730     68/push 1/imm32/is-atom?:true
15731     68/push 0x11/imm32/alloc-id:fake:payload
15732     89/<- %ecx 4/r32/esp
15733 $test-emit-subx-stmt-primitive:initialize-var:
15734     # var var-foo/ecx: (payload var) = var(type)
15735     68/push 0/imm32/no-register
15736     68/push 0/imm32/no-register
15737     68/push -8/imm32/stack-offset
15738     68/push 1/imm32/block-depth
15739     51/push-ecx/type
15740     68/push 0x11/imm32/alloc-id:fake
15741     68/push 0/imm32/name
15742     68/push 0/imm32/name
15743     68/push 0x11/imm32/alloc-id:fake:payload
15744     89/<- %ecx 4/r32/esp
15745 $test-emit-subx-stmt-primitive:initialize-var-name:
15746     # var-foo->name = "foo"
15747     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15748     (copy-array Heap "foo" %eax)
15749 $test-emit-subx-stmt-primitive:initialize-stmt-var:
15750     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
15751     68/push 0/imm32/is-deref:false
15752     68/push 0/imm32/next
15753     68/push 0/imm32/next
15754     51/push-ecx/var-foo
15755     68/push 0x11/imm32/alloc-id:fake
15756     68/push 0x11/imm32/alloc-id:fake:payload
15757     89/<- %ebx 4/r32/esp
15758 $test-emit-subx-stmt-primitive:initialize-stmt:
15759     # var stmt/esi: (addr statement)
15760     68/push 0/imm32/no-outputs
15761     68/push 0/imm32/no-outputs
15762     53/push-ebx/inouts
15763     68/push 0x11/imm32/alloc-id:fake
15764     68/push 0/imm32/operation
15765     68/push 0/imm32/operation
15766     68/push 1/imm32/tag
15767     89/<- %esi 4/r32/esp
15768 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
15769     # stmt->operation = "increment"
15770     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15771     (copy-array Heap "increment" %eax)
15772 $test-emit-subx-stmt-primitive:initialize-primitive:
15773     # var primitives/ebx: (addr primitive)
15774     68/push 0/imm32/next
15775     68/push 0/imm32/next
15776     68/push 0/imm32/output-is-write-only
15777     68/push 0/imm32/no-disp32
15778     68/push 0/imm32/no-imm32
15779     68/push 0/imm32/no-r32
15780     68/push 1/imm32/rm32-is-first-inout
15781     68/push 0/imm32/subx-name
15782     68/push 0/imm32/subx-name
15783     68/push 0/imm32/no-outputs
15784     68/push 0/imm32/no-outputs
15785     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
15786     68/push 0x11/imm32/alloc-id:fake
15787     68/push 0/imm32/name
15788     68/push 0/imm32/name
15789     89/<- %ebx 4/r32/esp
15790 $test-emit-subx-stmt-primitive:initialize-primitive-name:
15791     # primitives->name = "increment"
15792     (copy-array Heap "increment" %ebx)  # Primitive-name
15793 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
15794     # primitives->subx-name = "ff 0/subop/increment"
15795     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
15796     (copy-array Heap "ff 0/subop/increment" %eax)
15797     # convert
15798     c7 0/subop/copy *Curr-block-depth 0/imm32
15799     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
15800     (flush _test-output-buffered-file)
15801 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15807     # check output
15808     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
15809     # . epilogue
15810     89/<- %esp 5/r32/ebp
15811     5d/pop-to-ebp
15812     c3/return
15813 
15814 test-emit-subx-stmt-primitive-register:
15815     # Primitive operation on a variable in a register.
15816     #   foo <- increment
15817     # =>
15818     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
15819     #
15820     # There's a variable on the var stack as follows:
15821     #   name: 'foo'
15822     #   type: int
15823     #   register: 'eax'
15824     #
15825     # There's a primitive with this info:
15826     #   name: 'increment'
15827     #   out: int/reg
15828     #   value: 'ff 0/subop/increment'
15829     #
15830     # . prologue
15831     55/push-ebp
15832     89/<- %ebp 4/r32/esp
15833     # setup
15834     (clear-stream _test-output-stream)
15835     (clear-stream $_test-output-buffered-file->buffer)
15836 $test-emit-subx-stmt-primitive-register:initialize-type:
15837     # var type/ecx: (payload tree type-id) = int
15838     68/push 0/imm32/right:null
15839     68/push 0/imm32/right:null
15840     68/push 0/imm32/left:unused
15841     68/push 1/imm32/value:int
15842     68/push 1/imm32/is-atom?:true
15843     68/push 0x11/imm32/alloc-id:fake:payload
15844     89/<- %ecx 4/r32/esp
15845 $test-emit-subx-stmt-primitive-register:initialize-var:
15846     # var var-foo/ecx: (payload var)
15847     68/push 0/imm32/register
15848     68/push 0/imm32/register
15849     68/push 0/imm32/no-stack-offset
15850     68/push 1/imm32/block-depth
15851     51/push-ecx
15852     68/push 0x11/imm32/alloc-id:fake
15853     68/push 0/imm32/name
15854     68/push 0/imm32/name
15855     68/push 0x11/imm32/alloc-id:fake:payload
15856     89/<- %ecx 4/r32/esp
15857 $test-emit-subx-stmt-primitive-register:initialize-var-name:
15858     # var-foo->name = "foo"
15859     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15860     (copy-array Heap "foo" %eax)
15861 $test-emit-subx-stmt-primitive-register:initialize-var-register:
15862     # var-foo->register = "eax"
15863     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15864     (copy-array Heap "eax" %eax)
15865 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
15866     # var operand/ebx: (payload stmt-var)
15867     68/push 0/imm32/is-deref:false
15868     68/push 0/imm32/next
15869     68/push 0/imm32/next
15870     51/push-ecx/var-foo
15871     68/push 0x11/imm32/alloc-id:fake
15872     68/push 0x11/imm32/alloc-id:fake:payload
15873     89/<- %ebx 4/r32/esp
15874 $test-emit-subx-stmt-primitive-register:initialize-stmt:
15875     # var stmt/esi: (addr statement)
15876     53/push-ebx/outputs
15877     68/push 0x11/imm32/alloc-id:fake
15878     68/push 0/imm32/no-inouts
15879     68/push 0/imm32/no-inouts
15880     68/push 0/imm32/operation
15881     68/push 0/imm32/operation
15882     68/push 1/imm32
15883     89/<- %esi 4/r32/esp
15884 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
15885     # stmt->operation = "increment"
15886     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15887     (copy-array Heap "increment" %eax)
15888 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
15889     # var formal-var/ebx: (payload var)
15890     68/push 0/imm32/register
15891     68/push 0/imm32/register
15892     68/push 0/imm32/no-stack-offset
15893     68/push 1/imm32/block-depth
15894     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
15895     68/push 0x11/imm32/alloc-id:fake
15896     68/push 0/imm32/name
15897     68/push 0/imm32/name
15898     68/push 0x11/imm32/alloc-id:fake:payload
15899     89/<- %ebx 4/r32/esp
15900 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
15901     # formal-var->name = "dummy"
15902     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
15903     (copy-array Heap "dummy" %eax)
15904 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
15905     # formal-var->register = "*"
15906     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
15907     (copy-array Heap "*" %eax)  # Any-register
15908 $test-emit-subx-stmt-primitive-register:initialize-var-list:
15909     # var formal-outputs/ebx: (payload list var)
15910     68/push 0/imm32/next
15911     68/push 0/imm32/next
15912     53/push-ebx/formal-var
15913     68/push 0x11/imm32/alloc-id:fake
15914     68/push 0x11/imm32/alloc-id:fake:payload
15915     89/<- %ebx 4/r32/esp
15916 $test-emit-subx-stmt-primitive-register:initialize-primitive:
15917     # var primitives/ebx: (addr primitive)
15918     68/push 0/imm32/next
15919     68/push 0/imm32/next
15920     68/push 0/imm32/output-is-write-only
15921     68/push 0/imm32/no-disp32
15922     68/push 0/imm32/no-imm32
15923     68/push 0/imm32/no-r32
15924     68/push 3/imm32/rm32-is-first-output
15925     68/push 0/imm32/subx-name
15926     68/push 0/imm32/subx-name
15927     53/push-ebx/outputs
15928     68/push 0x11/imm32/alloc-id:fake
15929     68/push 0/imm32/no-inouts
15930     68/push 0/imm32/no-inouts
15931     68/push 0/imm32/name
15932     68/push 0/imm32/name
15933     89/<- %ebx 4/r32/esp
15934 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
15935     # primitives->name = "increment"
15936     (copy-array Heap "increment" %ebx)  # Primitive-name
15937 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
15938     # primitives->subx-name = "ff 0/subop/increment"
15939     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
15940     (copy-array Heap "ff 0/subop/increment" %eax)
15941     # convert
15942     c7 0/subop/copy *Curr-block-depth 0/imm32
15943     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
15944     (flush _test-output-buffered-file)
15945 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15951     # check output
15952     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
15953     # . epilogue
15954     89/<- %esp 5/r32/ebp
15955     5d/pop-to-ebp
15956     c3/return
15957 
15958 test-emit-subx-stmt-select-primitive:
15959     # Select the right primitive between overloads.
15960     #   foo <- increment
15961     # =>
15962     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
15963     #
15964     # There's a variable on the var stack as follows:
15965     #   name: 'foo'
15966     #   type: int
15967     #   register: 'eax'
15968     #
15969     # There's two primitives, as follows:
15970     #   - name: 'increment'
15971     #     out: int/reg
15972     #     value: 'ff 0/subop/increment'
15973     #   - name: 'increment'
15974     #     inout: int/mem
15975     #     value: 'ff 0/subop/increment'
15976     #
15977     # . prologue
15978     55/push-ebp
15979     89/<- %ebp 4/r32/esp
15980     # setup
15981     (clear-stream _test-output-stream)
15982     (clear-stream $_test-output-buffered-file->buffer)
15983 $test-emit-subx-stmt-select-primitive:initialize-type:
15984     # var type/ecx: (payload tree type-id) = int
15985     68/push 0/imm32/right:null
15986     68/push 0/imm32/right:null
15987     68/push 0/imm32/left:unused
15988     68/push 1/imm32/value:int
15989     68/push 1/imm32/is-atom?:true
15990     68/push 0x11/imm32/alloc-id:fake:payload
15991     89/<- %ecx 4/r32/esp
15992 $test-emit-subx-stmt-select-primitive:initialize-var:
15993     # var var-foo/ecx: (payload var)
15994     68/push 0/imm32/register
15995     68/push 0/imm32/register
15996     68/push 0/imm32/no-stack-offset
15997     68/push 1/imm32/block-depth
15998     51/push-ecx
15999     68/push 0x11/imm32/alloc-id:fake
16000     68/push 0/imm32/name
16001     68/push 0/imm32/name
16002     68/push 0x11/imm32/alloc-id:fake:payload
16003     89/<- %ecx 4/r32/esp
16004 $test-emit-subx-stmt-select-primitive:initialize-var-name:
16005     # var-foo->name = "foo"
16006     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16007     (copy-array Heap "foo" %eax)
16008 $test-emit-subx-stmt-select-primitive:initialize-var-register:
16009     # var-foo->register = "eax"
16010     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16011     (copy-array Heap "eax" %eax)
16012 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
16013     # var operand/ebx: (payload stmt-var)
16014     68/push 0/imm32/is-deref:false
16015     68/push 0/imm32/next
16016     68/push 0/imm32/next
16017     51/push-ecx/var-foo
16018     68/push 0x11/imm32/alloc-id:fake
16019     68/push 0x11/imm32/alloc-id:fake:payload
16020     89/<- %ebx 4/r32/esp
16021 $test-emit-subx-stmt-select-primitive:initialize-stmt:
16022     # var stmt/esi: (addr statement)
16023     53/push-ebx/outputs
16024     68/push 0x11/imm32/alloc-id:fake
16025     68/push 0/imm32/no-inouts
16026     68/push 0/imm32/no-inouts
16027     68/push 0/imm32/operation
16028     68/push 0/imm32/operation
16029     68/push 1/imm32
16030     89/<- %esi 4/r32/esp
16031 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
16032     # stmt->operation = "increment"
16033     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16034     (copy-array Heap "increment" %eax)
16035 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
16036     # var formal-var/ebx: (payload var)
16037     68/push 0/imm32/register
16038     68/push 0/imm32/register
16039     68/push 0/imm32/no-stack-offset
16040     68/push 1/imm32/block-depth
16041     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
16042     68/push 0x11/imm32/alloc-id:fake
16043     68/push 0/imm32/name
16044     68/push 0/imm32/name
16045     68/push 0x11/imm32/alloc-id:fake:payload
16046     89/<- %ebx 4/r32/esp
16047 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
16048     # formal-var->name = "dummy"
16049     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
16050     (copy-array Heap "dummy" %eax)
16051 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
16052     # formal-var->register = "*"
16053     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
16054     (copy-array Heap "*" %eax)  # Any-register
16055 $test-emit-subx-stmt-select-primitive:initialize-var-list:
16056     # var formal-outputs/ebx: (payload list var)
16057     68/push 0/imm32/next
16058     68/push 0/imm32/next
16059     53/push-ebx/formal-var
16060     68/push 0x11/imm32/alloc-id:fake
16061     68/push 0x11/imm32/alloc-id:fake:payload
16062     89/<- %ebx 4/r32/esp
16063 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
16064     # var primitive2/edi: (payload primitive)
16065     68/push 0/imm32/next
16066     68/push 0/imm32/next
16067     68/push 0/imm32/output-is-write-only
16068     68/push 0/imm32/no-disp32
16069     68/push 0/imm32/no-imm32
16070     68/push 0/imm32/no-r32
16071     68/push 3/imm32/rm32-is-first-output
16072     68/push 0/imm32/subx-name
16073     68/push 0/imm32/subx-name
16074     53/push-ebx/outputs
16075     68/push 0x11/imm32/alloc-id:fake
16076     68/push 0/imm32/no-inouts
16077     68/push 0/imm32/no-inouts
16078     68/push 0/imm32/name
16079     68/push 0/imm32/name
16080     68/push 0x11/imm32/alloc-id:fake:payload
16081     89/<- %edi 4/r32/esp
16082 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
16083     # primitives->name = "increment"
16084     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
16085     (copy-array Heap "increment" %eax)
16086 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
16087     # primitives->subx-name = "ff 0/subop/increment"
16088     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
16089     (copy-array Heap "ff 0/subop/increment" %eax)
16090 $test-emit-subx-stmt-select-primitive:initialize-primitive:
16091     # var primitives/ebx: (addr primitive)
16092     57/push-edi
16093     68/push 0x11/imm32/alloc-id:fake
16094     68/push 0/imm32/output-is-write-only
16095     68/push 0/imm32/no-disp32
16096     68/push 0/imm32/no-imm32
16097     68/push 0/imm32/no-r32
16098     68/push 1/imm32/rm32-is-first-inout
16099     68/push 0/imm32/subx-name
16100     68/push 0/imm32/subx-name
16101     68/push 0/imm32/no-outputs
16102     68/push 0/imm32/no-outputs
16103     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
16104     68/push 0x11/imm32/alloc-id:fake
16105     68/push 0/imm32/name
16106     68/push 0/imm32/name
16107     89/<- %ebx 4/r32/esp
16108 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
16109     # primitives->name = "increment"
16110     (copy-array Heap "increment" %ebx)  # Primitive-name
16111 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
16112     # primitives->subx-name = "ff 0/subop/increment"
16113     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
16114     (copy-array Heap "ff 0/subop/increment" %eax)
16115     # convert
16116     c7 0/subop/copy *Curr-block-depth 0/imm32
16117     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
16118     (flush _test-output-buffered-file)
16119 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16125     # check output
16126     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
16127     # . epilogue
16128     89/<- %esp 5/r32/ebp
16129     5d/pop-to-ebp
16130     c3/return
16131 
16132 test-emit-subx-stmt-select-primitive-2:
16133     # Select the right primitive between overloads.
16134     #   increment foo
16135     # =>
16136     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
16137     #
16138     # There's a variable on the var stack as follows:
16139     #   name: 'foo'
16140     #   type: int
16141     #   register: 'eax'
16142     #
16143     # There's two primitives, as follows:
16144     #   - name: 'increment'
16145     #     out: int/reg
16146     #     value: 'ff 0/subop/increment'
16147     #   - name: 'increment'
16148     #     inout: int/mem
16149     #     value: 'ff 0/subop/increment'
16150     #
16151     # . prologue
16152     55/push-ebp
16153     89/<- %ebp 4/r32/esp
16154     # setup
16155     (clear-stream _test-output-stream)
16156     (clear-stream $_test-output-buffered-file->buffer)
16157 $test-emit-subx-stmt-select-primitive-2:initialize-type:
16158     # var type/ecx: (payload tree type-id) = int
16159     68/push 0/imm32/right:null
16160     68/push 0/imm32/right:null
16161     68/push 0/imm32/left:unused
16162     68/push 1/imm32/value:int
16163     68/push 1/imm32/is-atom?:true
16164     68/push 0x11/imm32/alloc-id:fake:payload
16165     89/<- %ecx 4/r32/esp
16166 $test-emit-subx-stmt-select-primitive-2:initialize-var:
16167     # var var-foo/ecx: (payload var)
16168     68/push 0/imm32/register
16169     68/push 0/imm32/register
16170     68/push 0/imm32/no-stack-offset
16171     68/push 1/imm32/block-depth
16172     51/push-ecx
16173     68/push 0x11/imm32/alloc-id:fake
16174     68/push 0/imm32/name
16175     68/push 0/imm32/name
16176     68/push 0x11/imm32/alloc-id:fake:payload
16177     89/<- %ecx 4/r32/esp
16178 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
16179     # var-foo->name = "foo"
16180     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16181     (copy-array Heap "foo" %eax)
16182 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
16183     # var-foo->register = "eax"
16184     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16185     (copy-array Heap "eax" %eax)
16186 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
16187     # var operand/ebx: (payload stmt-var)
16188     68/push 0/imm32/is-deref:false
16189     68/push 0/imm32/next
16190     68/push 0/imm32/next
16191     51/push-ecx/var-foo
16192     68/push 0x11/imm32/alloc-id:fake
16193     68/push 0x11/imm32/alloc-id:fake:payload
16194     89/<- %ebx 4/r32/esp
16195 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
16196     # var stmt/esi: (addr statement)
16197     68/push 0/imm32/no-outputs
16198     68/push 0/imm32/no-outputs
16199     53/push-ebx/inouts
16200     68/push 0x11/imm32/alloc-id:fake
16201     68/push 0/imm32/operation
16202     68/push 0/imm32/operation
16203     68/push 1/imm32
16204     89/<- %esi 4/r32/esp
16205 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
16206     # stmt->operation = "increment"
16207     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16208     (copy-array Heap "increment" %eax)
16209 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
16210     # var formal-var/ebx: (payload var)
16211     68/push 0/imm32/register
16212     68/push 0/imm32/register
16213     68/push 0/imm32/no-stack-offset
16214     68/push 1/imm32/block-depth
16215     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
16216     68/push 0x11/imm32/alloc-id:fake
16217     68/push 0/imm32/name
16218     68/push 0/imm32/name
16219     68/push 0x11/imm32/alloc-id:fake:payload
16220     89/<- %ebx 4/r32/esp
16221 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
16222     # formal-var->name = "dummy"
16223     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
16224     (copy-array Heap "dummy" %eax)
16225 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
16226     # formal-var->register = "*"
16227     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
16228     (copy-array Heap "*" %eax)  # Any-register
16229 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
16230     # var formal-outputs/ebx: (payload list stmt-var)
16231     68/push 0/imm32/next
16232     68/push 0/imm32/next
16233     53/push-ebx/formal-var
16234     68/push 0x11/imm32/alloc-id:fake
16235     68/push 0x11/imm32/alloc-id:fake:payload
16236     89/<- %ebx 4/r32/esp
16237 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
16238     # var primitive2/edi: (payload primitive)
16239     68/push 0/imm32/next
16240     68/push 0/imm32/next
16241     68/push 0/imm32/output-is-write-only
16242     68/push 0/imm32/no-disp32
16243     68/push 0/imm32/no-imm32
16244     68/push 0/imm32/no-r32
16245     68/push 3/imm32/rm32-is-first-output
16246     68/push 0/imm32/subx-name
16247     68/push 0/imm32/subx-name
16248     53/push-ebx/outputs
16249     68/push 0x11/imm32/alloc-id:fake
16250     68/push 0/imm32/no-inouts
16251     68/push 0/imm32/no-inouts
16252     68/push 0/imm32/name
16253     68/push 0/imm32/name
16254     68/push 0x11/imm32/alloc-id:fake:payload
16255     89/<- %edi 4/r32/esp
16256 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
16257     # primitives->name = "increment"
16258     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
16259     (copy-array Heap "increment" %eax)
16260 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
16261     # primitives->subx-name = "ff 0/subop/increment"
16262     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
16263     (copy-array Heap "ff 0/subop/increment" %eax)
16264 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
16265     # var primitives/ebx: (addr primitive)
16266     57/push-edi
16267     68/push 0x11/imm32/alloc-id:fake
16268     68/push 0/imm32/output-is-write-only
16269     68/push 0/imm32/no-disp32
16270     68/push 0/imm32/no-imm32
16271     68/push 0/imm32/no-r32
16272     68/push 1/imm32/rm32-is-first-inout
16273     68/push 0/imm32/subx-name
16274     68/push 0/imm32/subx-name
16275     68/push 0/imm32/no-outputs
16276     68/push 0/imm32/no-outputs
16277     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
16278     68/push 0x11/imm32/alloc-id:fake
16279     68/push 0/imm32/name
16280     68/push 0/imm32/name
16281     89/<- %ebx 4/r32/esp
16282 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
16283     # primitives->name = "increment"
16284     (copy-array Heap "increment" %ebx)  # Primitive-name
16285 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
16286     # primitives->subx-name = "ff 0/subop/increment"
16287     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
16288     (copy-array Heap "ff 0/subop/increment" %eax)
16289     # convert
16290     c7 0/subop/copy *Curr-block-depth 0/imm32
16291     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
16292     (flush _test-output-buffered-file)
16293 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16299     # check output
16300     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
16301     # . epilogue
16302     89/<- %esp 5/r32/ebp
16303     5d/pop-to-ebp
16304     c3/return
16305 
16306 test-increment-register:
16307     # Select the right register between overloads.
16308     #   foo <- increment
16309     # =>
16310     #   50/increment-eax
16311     #
16312     # There's a variable on the var stack as follows:
16313     #   name: 'foo'
16314     #   type: int
16315     #   register: 'eax'
16316     #
16317     # Primitives are the global definitions.
16318     #
16319     # . prologue
16320     55/push-ebp
16321     89/<- %ebp 4/r32/esp
16322     # setup
16323     (clear-stream _test-output-stream)
16324     (clear-stream $_test-output-buffered-file->buffer)
16325 $test-increment-register:initialize-type:
16326     # var type/ecx: (payload tree type-id) = int
16327     68/push 0/imm32/right:null
16328     68/push 0/imm32/right:null
16329     68/push 0/imm32/left:unused
16330     68/push 1/imm32/value:int
16331     68/push 1/imm32/is-atom?:true
16332     68/push 0x11/imm32/alloc-id:fake:payload
16333     89/<- %ecx 4/r32/esp
16334 $test-increment-register:initialize-var:
16335     # var var-foo/ecx: (payload var)
16336     68/push 0/imm32/register
16337     68/push 0/imm32/register
16338     68/push 0/imm32/no-stack-offset
16339     68/push 1/imm32/block-depth
16340     51/push-ecx
16341     68/push 0x11/imm32/alloc-id:fake
16342     68/push 0/imm32/name
16343     68/push 0/imm32/name
16344     68/push 0x11/imm32/alloc-id:fake:payload
16345     89/<- %ecx 4/r32/esp
16346 $test-increment-register:initialize-var-name:
16347     # var-foo->name = "foo"
16348     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16349     (copy-array Heap "foo" %eax)
16350 $test-increment-register:initialize-var-register:
16351     # var-foo->register = "eax"
16352     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16353     (copy-array Heap "eax" %eax)
16354 $test-increment-register:initialize-stmt-var:
16355     # var operand/ebx: (payload stmt-var)
16356     68/push 0/imm32/is-deref:false
16357     68/push 0/imm32/next
16358     68/push 0/imm32/next
16359     51/push-ecx/var-foo
16360     68/push 0x11/imm32/alloc-id:fake
16361     68/push 0x11/imm32/alloc-id:fake:payload
16362     89/<- %ebx 4/r32/esp
16363 $test-increment-register:initialize-stmt:
16364     # var stmt/esi: (addr statement)
16365     53/push-ebx/outputs
16366     68/push 0x11/imm32/alloc-id:fake
16367     68/push 0/imm32/no-inouts
16368     68/push 0/imm32/no-inouts
16369     68/push 0/imm32/operation
16370     68/push 0/imm32/operation
16371     68/push 1/imm32
16372     89/<- %esi 4/r32/esp
16373 $test-increment-register:initialize-stmt-operation:
16374     # stmt->operation = "increment"
16375     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16376     (copy-array Heap "increment" %eax)
16377     # convert
16378     c7 0/subop/copy *Curr-block-depth 0/imm32
16379     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16380     (flush _test-output-buffered-file)
16381 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16387     # check output
16388     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
16389     # . epilogue
16390     89/<- %esp 5/r32/ebp
16391     5d/pop-to-ebp
16392     c3/return
16393 
16394 test-add-reg-to-reg:
16395     #   var1/reg <- add var2/reg
16396     # =>
16397     #   01/add-to %var1 var2
16398     #
16399     # . prologue
16400     55/push-ebp
16401     89/<- %ebp 4/r32/esp
16402     # setup
16403     (clear-stream _test-output-stream)
16404     (clear-stream $_test-output-buffered-file->buffer)
16405 $test-add-reg-to-reg:initialize-type:
16406     # var type/ecx: (payload tree type-id) = int
16407     68/push 0/imm32/right:null
16408     68/push 0/imm32/right:null
16409     68/push 0/imm32/left:unused
16410     68/push 1/imm32/value:int
16411     68/push 1/imm32/is-atom?:true
16412     68/push 0x11/imm32/alloc-id:fake:payload
16413     89/<- %ecx 4/r32/esp
16414 $test-add-reg-to-reg:initialize-var1:
16415     # var var1/ecx: (payload var)
16416     68/push 0/imm32/register
16417     68/push 0/imm32/register
16418     68/push 0/imm32/no-stack-offset
16419     68/push 1/imm32/block-depth
16420     51/push-ecx
16421     68/push 0x11/imm32/alloc-id:fake
16422     68/push 0/imm32/name
16423     68/push 0/imm32/name
16424     68/push 0x11/imm32/alloc-id:fake:payload
16425     89/<- %ecx 4/r32/esp
16426 $test-add-reg-to-reg:initialize-var1-name:
16427     # var1->name = "var1"
16428     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16429     (copy-array Heap "var1" %eax)
16430 $test-add-reg-to-reg:initialize-var1-register:
16431     # var1->register = "eax"
16432     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16433     (copy-array Heap "eax" %eax)
16434 $test-add-reg-to-reg:initialize-var2:
16435     # var var2/edx: (payload var)
16436     68/push 0/imm32/register
16437     68/push 0/imm32/register
16438     68/push 0/imm32/no-stack-offset
16439     68/push 1/imm32/block-depth
16440     ff 6/subop/push *(ecx+0x10)
16441     68/push 0x11/imm32/alloc-id:fake
16442     68/push 0/imm32/name
16443     68/push 0/imm32/name
16444     68/push 0x11/imm32/alloc-id:fake:payload
16445     89/<- %edx 4/r32/esp
16446 $test-add-reg-to-reg:initialize-var2-name:
16447     # var2->name = "var2"
16448     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16449     (copy-array Heap "var2" %eax)
16450 $test-add-reg-to-reg:initialize-var2-register:
16451     # var2->register = "ecx"
16452     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
16453     (copy-array Heap "ecx" %eax)
16454 $test-add-reg-to-reg:initialize-inouts:
16455     # var inouts/esi: (payload stmt-var) = [var2]
16456     68/push 0/imm32/is-deref:false
16457     68/push 0/imm32/next
16458     68/push 0/imm32/next
16459     52/push-edx/var2
16460     68/push 0x11/imm32/alloc-id:fake
16461     68/push 0x11/imm32/alloc-id:fake:payload
16462     89/<- %esi 4/r32/esp
16463 $test-add-reg-to-reg:initialize-outputs:
16464     # var outputs/edi: (payload stmt-var) = [var1]
16465     68/push 0/imm32/is-deref:false
16466     68/push 0/imm32/next
16467     68/push 0/imm32/next
16468     51/push-ecx/var1
16469     68/push 0x11/imm32/alloc-id:fake
16470     68/push 0x11/imm32/alloc-id:fake:payload
16471     89/<- %edi 4/r32/esp
16472 $test-add-reg-to-reg:initialize-stmt:
16473     # var stmt/esi: (addr statement)
16474     68/push 0/imm32/next
16475     68/push 0/imm32/next
16476     57/push-edi/outputs
16477     68/push 0x11/imm32/alloc-id:fake
16478     56/push-esi/inouts
16479     68/push 0x11/imm32/alloc-id:fake
16480     68/push 0/imm32/operation
16481     68/push 0/imm32/operation
16482     68/push 1/imm32/tag:stmt1
16483     89/<- %esi 4/r32/esp
16484 $test-add-reg-to-reg:initialize-stmt-operation:
16485     # stmt->operation = "add"
16486     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16487     (copy-array Heap "add" %eax)
16488     # convert
16489     c7 0/subop/copy *Curr-block-depth 0/imm32
16490     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16491     (flush _test-output-buffered-file)
16492 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16498     # check output
16499     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
16500     # . epilogue
16501     89/<- %esp 5/r32/ebp
16502     5d/pop-to-ebp
16503     c3/return
16504 
16505 test-add-reg-to-mem:
16506     #   add-to var1 var2/reg
16507     # =>
16508     #   01/add-to *(ebp+__) var2
16509     #
16510     # . prologue
16511     55/push-ebp
16512     89/<- %ebp 4/r32/esp
16513     # setup
16514     (clear-stream _test-output-stream)
16515     (clear-stream $_test-output-buffered-file->buffer)
16516 $test-add-reg-to-mem:initialize-type:
16517     # var type/ecx: (payload tree type-id) = int
16518     68/push 0/imm32/right:null
16519     68/push 0/imm32/right:null
16520     68/push 0/imm32/left:unused
16521     68/push 1/imm32/value:int
16522     68/push 1/imm32/is-atom?:true
16523     68/push 0x11/imm32/alloc-id:fake:payload
16524     89/<- %ecx 4/r32/esp
16525 $test-add-reg-to-mem:initialize-var1:
16526     # var var1/ecx: (payload var)
16527     68/push 0/imm32/register
16528     68/push 0/imm32/register
16529     68/push 8/imm32/stack-offset
16530     68/push 1/imm32/block-depth
16531     51/push-ecx
16532     68/push 0x11/imm32/alloc-id:fake
16533     68/push 0/imm32/name
16534     68/push 0/imm32/name
16535     68/push 0x11/imm32/alloc-id:fake:payload
16536     89/<- %ecx 4/r32/esp
16537 $test-add-reg-to-mem:initialize-var1-name:
16538     # var1->name = "var1"
16539     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16540     (copy-array Heap "var1" %eax)
16541 $test-add-reg-to-mem:initialize-var2:
16542     # var var2/edx: (payload var)
16543     68/push 0/imm32/register
16544     68/push 0/imm32/register
16545     68/push 0/imm32/no-stack-offset
16546     68/push 1/imm32/block-depth
16547     ff 6/subop/push *(ecx+0x10)
16548     68/push 0x11/imm32/alloc-id:fake
16549     68/push 0/imm32/name
16550     68/push 0/imm32/name
16551     68/push 0x11/imm32/alloc-id:fake:payload
16552     89/<- %edx 4/r32/esp
16553 $test-add-reg-to-mem:initialize-var2-name:
16554     # var2->name = "var2"
16555     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16556     (copy-array Heap "var2" %eax)
16557 $test-add-reg-to-mem:initialize-var2-register:
16558     # var2->register = "ecx"
16559     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
16560     (copy-array Heap "ecx" %eax)
16561 $test-add-reg-to-mem:initialize-inouts:
16562     # var inouts/esi: (payload stmt-var) = [var2]
16563     68/push 0/imm32/is-deref:false
16564     68/push 0/imm32/next
16565     68/push 0/imm32/next
16566     52/push-edx/var2
16567     68/push 0x11/imm32/alloc-id:fake
16568     68/push 0x11/imm32/alloc-id:fake:payload
16569     89/<- %esi 4/r32/esp
16570     # inouts = [var1, var2]
16571     68/push 0/imm32/is-deref:false
16572     56/push-esi/next
16573     68/push 0x11/imm32/alloc-id:fake
16574     51/push-ecx/var1
16575     68/push 0x11/imm32/alloc-id:fake
16576     68/push 0x11/imm32/alloc-id:fake:payload
16577     89/<- %esi 4/r32/esp
16578 $test-add-reg-to-mem:initialize-stmt:
16579     # var stmt/esi: (addr statement)
16580     68/push 0/imm32/next
16581     68/push 0/imm32/next
16582     68/push 0/imm32/outputs
16583     68/push 0/imm32/outputs
16584     56/push-esi/inouts
16585     68/push 0x11/imm32/alloc-id:fake
16586     68/push 0/imm32/operation
16587     68/push 0/imm32/operation
16588     68/push 1/imm32/tag:stmt1
16589     89/<- %esi 4/r32/esp
16590 $test-add-reg-to-mem:initialize-stmt-operation:
16591     # stmt->operation = "add-to"
16592     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16593     (copy-array Heap "add-to" %eax)
16594     # convert
16595     c7 0/subop/copy *Curr-block-depth 0/imm32
16596     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16597     (flush _test-output-buffered-file)
16598 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16604     # check output
16605     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
16606     # . epilogue
16607     89/<- %esp 5/r32/ebp
16608     5d/pop-to-ebp
16609     c3/return
16610 
16611 test-add-mem-to-reg:
16612     #   var1/reg <- add var2
16613     # =>
16614     #   03/add *(ebp+__) var1
16615     #
16616     # . prologue
16617     55/push-ebp
16618     89/<- %ebp 4/r32/esp
16619     # setup
16620     (clear-stream _test-output-stream)
16621     (clear-stream $_test-output-buffered-file->buffer)
16622 $test-add-mem-to-reg:initialize-type:
16623     # var type/ecx: (payload tree type-id) = int
16624     68/push 0/imm32/right:null
16625     68/push 0/imm32/right:null
16626     68/push 0/imm32/left:unused
16627     68/push 1/imm32/value:int
16628     68/push 1/imm32/is-atom?:true
16629     68/push 0x11/imm32/alloc-id:fake:payload
16630     89/<- %ecx 4/r32/esp
16631 $test-add-mem-to-reg:initialize-var:
16632     # var var1/ecx: (payload var)
16633     68/push 0/imm32/register
16634     68/push 0/imm32/register
16635     68/push 0/imm32/no-stack-offset
16636     68/push 1/imm32/block-depth
16637     51/push-ecx
16638     68/push 0x11/imm32/alloc-id:fake
16639     68/push 0/imm32/name
16640     68/push 0/imm32/name
16641     68/push 0x11/imm32/alloc-id:fake:payload
16642     89/<- %ecx 4/r32/esp
16643 $test-add-mem-to-reg:initialize-var-name:
16644     # var1->name = "foo"
16645     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16646     (copy-array Heap "var1" %eax)
16647 $test-add-mem-to-reg:initialize-var-register:
16648     # var1->register = "eax"
16649     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16650     (copy-array Heap "eax" %eax)
16651 $test-add-mem-to-reg:initialize-var2:
16652     # var var2/edx: (payload var)
16653     68/push 0/imm32/register
16654     68/push 0/imm32/register
16655     68/push 8/imm32/stack-offset
16656     68/push 1/imm32/block-depth
16657     ff 6/subop/push *(ecx+0x10)
16658     68/push 0x11/imm32/alloc-id:fake
16659     68/push 0/imm32/name
16660     68/push 0/imm32/name
16661     68/push 0x11/imm32/alloc-id:fake:payload
16662     89/<- %edx 4/r32/esp
16663 $test-add-mem-to-reg:initialize-var2-name:
16664     # var2->name = "var2"
16665     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16666     (copy-array Heap "var2" %eax)
16667 $test-add-mem-to-reg:initialize-inouts:
16668     # var inouts/esi: (payload stmt-var) = [var2]
16669     68/push 0/imm32/is-deref:false
16670     68/push 0/imm32/next
16671     68/push 0/imm32/next
16672     52/push-edx/var2
16673     68/push 0x11/imm32/alloc-id:fake
16674     68/push 0x11/imm32/alloc-id:fake:payload
16675     89/<- %esi 4/r32/esp
16676 $test-add-mem-to-reg:initialize-outputs:
16677     # var outputs/edi: (payload stmt-var) = [var1]
16678     68/push 0/imm32/is-deref:false
16679     68/push 0/imm32/next
16680     68/push 0/imm32/next
16681     51/push-ecx/var1
16682     68/push 0x11/imm32/alloc-id:fake
16683     68/push 0x11/imm32/alloc-id:fake:payload
16684     89/<- %edi 4/r32/esp
16685 $test-add-mem-to-reg:initialize-stmt:
16686     # var stmt/esi: (addr statement)
16687     68/push 0/imm32/next
16688     68/push 0/imm32/next
16689     57/push-edi/outputs
16690     68/push 0x11/imm32/alloc-id:fake
16691     56/push-esi/inouts
16692     68/push 0x11/imm32/alloc-id:fake
16693     68/push 0/imm32/operation
16694     68/push 0/imm32/operation
16695     68/push 1/imm32/tag:stmt1
16696     89/<- %esi 4/r32/esp
16697 $test-add-mem-to-reg:initialize-stmt-operation:
16698     # stmt->operation = "add"
16699     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16700     (copy-array Heap "add" %eax)
16701     # convert
16702     c7 0/subop/copy *Curr-block-depth 0/imm32
16703     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16704     (flush _test-output-buffered-file)
16705 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16711     # check output
16712     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
16713     # . epilogue
16714     89/<- %esp 5/r32/ebp
16715     5d/pop-to-ebp
16716     c3/return
16717 
16718 test-add-literal-to-eax:
16719     #   var1/eax <- add 0x34
16720     # =>
16721     #   05/add-to-eax 0x34/imm32
16722     #
16723     # . prologue
16724     55/push-ebp
16725     89/<- %ebp 4/r32/esp
16726     # setup
16727     (clear-stream _test-output-stream)
16728     (clear-stream $_test-output-buffered-file->buffer)
16729 $test-add-literal-to-eax:initialize-var-type:
16730     # var type/ecx: (payload tree type-id) = int
16731     68/push 0/imm32/right:null
16732     68/push 0/imm32/right:null
16733     68/push 0/imm32/left:unused
16734     68/push 1/imm32/value:int
16735     68/push 1/imm32/is-atom?:true
16736     68/push 0x11/imm32/alloc-id:fake:payload
16737     89/<- %ecx 4/r32/esp
16738 $test-add-literal-to-eax:initialize-var:
16739     # var v/ecx: (payload var)
16740     68/push 0/imm32/register
16741     68/push 0/imm32/register
16742     68/push 0/imm32/no-stack-offset
16743     68/push 1/imm32/block-depth
16744     51/push-ecx
16745     68/push 0x11/imm32/alloc-id:fake
16746     68/push 0/imm32/name
16747     68/push 0/imm32/name
16748     68/push 0x11/imm32/alloc-id:fake:payload
16749     89/<- %ecx 4/r32/esp
16750 $test-add-literal-to-eax:initialize-var-name:
16751     # v->name = "v"
16752     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16753     (copy-array Heap "v" %eax)
16754 $test-add-literal-to-eax:initialize-var-register:
16755     # v->register = "eax"
16756     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16757     (copy-array Heap "eax" %eax)
16758 $test-add-literal-to-eax:initialize-literal-type:
16759     # var type/edx: (payload tree type-id) = literal
16760     68/push 0/imm32/right:null
16761     68/push 0/imm32/right:null
16762     68/push 0/imm32/left:unused
16763     68/push 0/imm32/value:literal
16764     68/push 1/imm32/is-atom?:true
16765     68/push 0x11/imm32/alloc-id:fake:payload
16766     89/<- %edx 4/r32/esp
16767 $test-add-literal-to-eax:initialize-literal:
16768     # var l/edx: (payload var)
16769     68/push 0/imm32/register
16770     68/push 0/imm32/register
16771     68/push 0/imm32/no-stack-offset
16772     68/push 1/imm32/block-depth
16773     52/push-edx
16774     68/push 0x11/imm32/alloc-id:fake
16775     68/push 0/imm32/name
16776     68/push 0/imm32/name
16777     68/push 0x11/imm32/alloc-id:fake:payload
16778     89/<- %edx 4/r32/esp
16779 $test-add-literal-to-eax:initialize-literal-value:
16780     # l->name = "0x34"
16781     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16782     (copy-array Heap "0x34" %eax)
16783 $test-add-literal-to-eax:initialize-inouts:
16784     # var inouts/esi: (payload stmt-var) = [l]
16785     68/push 0/imm32/is-deref:false
16786     68/push 0/imm32/next
16787     68/push 0/imm32/next
16788     52/push-edx/l
16789     68/push 0x11/imm32/alloc-id:fake
16790     68/push 0x11/imm32/alloc-id:fake:payload
16791     89/<- %esi 4/r32/esp
16792 $test-add-literal-to-eax:initialize-outputs:
16793     # var outputs/edi: (payload stmt-var) = [v]
16794     68/push 0/imm32/is-deref:false
16795     68/push 0/imm32/next
16796     68/push 0/imm32/next
16797     51/push-ecx/v
16798     68/push 0x11/imm32/alloc-id:fake
16799     68/push 0x11/imm32/alloc-id:fake:payload
16800     89/<- %edi 4/r32/esp
16801 $test-add-literal-to-eax:initialize-stmt:
16802     # var stmt/esi: (addr statement)
16803     68/push 0/imm32/next
16804     68/push 0/imm32/next
16805     57/push-edi/outputs
16806     68/push 0x11/imm32/alloc-id:fake
16807     56/push-esi/inouts
16808     68/push 0x11/imm32/alloc-id:fake
16809     68/push 0/imm32/operation
16810     68/push 0/imm32/operation
16811     68/push 1/imm32/tag:stmt1
16812     89/<- %esi 4/r32/esp
16813 $test-add-literal-to-eax:initialize-stmt-operation:
16814     # stmt->operation = "add"
16815     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16816     (copy-array Heap "add" %eax)
16817     # convert
16818     c7 0/subop/copy *Curr-block-depth 0/imm32
16819     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16820     (flush _test-output-buffered-file)
16821 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16827     # check output
16828     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
16829     # . epilogue
16830     89/<- %esp 5/r32/ebp
16831     5d/pop-to-ebp
16832     c3/return
16833 
16834 test-add-literal-to-reg:
16835     #   var1/ecx <- add 0x34
16836     # =>
16837     #   81 0/subop/add %ecx 0x34/imm32
16838     #
16839     # . prologue
16840     55/push-ebp
16841     89/<- %ebp 4/r32/esp
16842     # setup
16843     (clear-stream _test-output-stream)
16844     (clear-stream $_test-output-buffered-file->buffer)
16845 $test-add-literal-to-reg:initialize-var-type:
16846     # var type/ecx: (payload tree type-id) = int
16847     68/push 0/imm32/right:null
16848     68/push 0/imm32/right:null
16849     68/push 0/imm32/left:unused
16850     68/push 1/imm32/value:int
16851     68/push 1/imm32/is-atom?:true
16852     68/push 0x11/imm32/alloc-id:fake:payload
16853     89/<- %ecx 4/r32/esp
16854 $test-add-literal-to-reg:initialize-var:
16855     # var v/ecx: (payload var)
16856     68/push 0/imm32/register
16857     68/push 0/imm32/register
16858     68/push 0/imm32/no-stack-offset
16859     68/push 1/imm32/block-depth
16860     51/push-ecx
16861     68/push 0x11/imm32/alloc-id:fake
16862     68/push 0/imm32/name
16863     68/push 0/imm32/name
16864     68/push 0x11/imm32/alloc-id:fake:payload
16865     89/<- %ecx 4/r32/esp
16866 $test-add-literal-to-reg:initialize-var-name:
16867     # v->name = "v"
16868     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16869     (copy-array Heap "v" %eax)
16870 $test-add-literal-to-reg:initialize-var-register:
16871     # v->register = "ecx"
16872     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16873     (copy-array Heap "ecx" %eax)
16874 $test-add-literal-to-reg:initialize-literal-type:
16875     # var type/edx: (payload tree type-id) = literal
16876     68/push 0/imm32/right:null
16877     68/push 0/imm32/right:null
16878     68/push 0/imm32/left:unused
16879     68/push 0/imm32/value:literal
16880     68/push 1/imm32/is-atom?:true
16881     68/push 0x11/imm32/alloc-id:fake:payload
16882     89/<- %edx 4/r32/esp
16883 $test-add-literal-to-reg:initialize-literal:
16884     # var l/edx: (payload var)
16885     68/push 0/imm32/register
16886     68/push 0/imm32/register
16887     68/push 0/imm32/no-stack-offset
16888     68/push 1/imm32/block-depth
16889     52/push-edx
16890     68/push 0x11/imm32/alloc-id:fake
16891     68/push 0/imm32/name
16892     68/push 0/imm32/name
16893     68/push 0x11/imm32/alloc-id:fake:payload
16894     89/<- %edx 4/r32/esp
16895 $test-add-literal-to-reg:initialize-literal-value:
16896     # l->name = "0x34"
16897     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16898     (copy-array Heap "0x34" %eax)
16899 $test-add-literal-to-reg:initialize-inouts:
16900     # var inouts/esi: (payload stmt-var) = [l]
16901     68/push 0/imm32/is-deref:false
16902     68/push 0/imm32/next
16903     68/push 0/imm32/next
16904     52/push-edx/l
16905     68/push 0x11/imm32/alloc-id:fake
16906     68/push 0x11/imm32/alloc-id:fake:payload
16907     89/<- %esi 4/r32/esp
16908 $test-add-literal-to-reg:initialize-outputs:
16909     # var outputs/edi: (payload stmt-var) = [v]
16910     68/push 0/imm32/is-deref:false
16911     68/push 0/imm32/next
16912     68/push 0/imm32/next
16913     51/push-ecx/v
16914     68/push 0x11/imm32/alloc-id:fake
16915     68/push 0x11/imm32/alloc-id:fake:payload
16916     89/<- %edi 4/r32/esp
16917 $test-add-literal-to-reg:initialize-stmt:
16918     # var stmt/esi: (addr statement)
16919     68/push 0/imm32/next
16920     68/push 0/imm32/next
16921     57/push-edi/outputs
16922     68/push 0x11/imm32/alloc-id:fake
16923     56/push-esi/inouts
16924     68/push 0x11/imm32/alloc-id:fake
16925     68/push 0/imm32/operation
16926     68/push 0/imm32/operation
16927     68/push 1/imm32/tag:stmt1
16928     89/<- %esi 4/r32/esp
16929 $test-add-literal-to-reg:initialize-stmt-operation:
16930     # stmt->operation = "add"
16931     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16932     (copy-array Heap "add" %eax)
16933     # convert
16934     c7 0/subop/copy *Curr-block-depth 0/imm32
16935     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16936     (flush _test-output-buffered-file)
16937 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16943     # check output
16944     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
16945     # . epilogue
16946     89/<- %esp 5/r32/ebp
16947     5d/pop-to-ebp
16948     c3/return
16949 
16950 test-add-literal-to-mem:
16951     #   add-to var1, 0x34
16952     # =>
16953     #   81 0/subop/add %eax 0x34/imm32
16954     #
16955     # . prologue
16956     55/push-ebp
16957     89/<- %ebp 4/r32/esp
16958     # setup
16959     (clear-stream _test-output-stream)
16960     (clear-stream $_test-output-buffered-file->buffer)
16961 $test-add-literal-to-mem:initialize-type:
16962     # var type/ecx: (payload tree type-id) = int
16963     68/push 0/imm32/right:null
16964     68/push 0/imm32/right:null
16965     68/push 0/imm32/left:unused
16966     68/push 1/imm32/value:int
16967     68/push 1/imm32/is-atom?:true
16968     68/push 0x11/imm32/alloc-id:fake:payload
16969     89/<- %ecx 4/r32/esp
16970 $test-add-literal-to-mem:initialize-var1:
16971     # var var1/ecx: (payload var)
16972     68/push 0/imm32/register
16973     68/push 0/imm32/register
16974     68/push 8/imm32/stack-offset
16975     68/push 1/imm32/block-depth
16976     51/push-ecx
16977     68/push 0x11/imm32/alloc-id:fake
16978     68/push 0/imm32/name
16979     68/push 0/imm32/name
16980     68/push 0x11/imm32/alloc-id:fake:payload
16981     89/<- %ecx 4/r32/esp
16982 $test-add-literal-to-mem:initialize-var1-name:
16983     # var1->name = "var1"
16984     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16985     (copy-array Heap "var1" %eax)
16986 $test-add-literal-to-mem:initialize-literal-type:
16987     # var type/edx: (payload tree type-id) = literal
16988     68/push 0/imm32/right:null
16989     68/push 0/imm32/right:null
16990     68/push 0/imm32/left:unused
16991     68/push 0/imm32/value:literal
16992     68/push 1/imm32/is-atom?:true
16993     68/push 0x11/imm32/alloc-id:fake:payload
16994     89/<- %edx 4/r32/esp
16995 $test-add-literal-to-mem:initialize-literal:
16996     # var l/edx: (payload var)
16997     68/push 0/imm32/register
16998     68/push 0/imm32/register
16999     68/push 0/imm32/no-stack-offset
17000     68/push 1/imm32/block-depth
17001     52/push-edx
17002     68/push 0x11/imm32/alloc-id:fake
17003     68/push 0/imm32/name
17004     68/push 0/imm32/name
17005     68/push 0x11/imm32/alloc-id:fake:payload
17006     89/<- %edx 4/r32/esp
17007 $test-add-literal-to-mem:initialize-literal-value:
17008     # l->name = "0x34"
17009     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17010     (copy-array Heap "0x34" %eax)
17011 $test-add-literal-to-mem:initialize-inouts:
17012     # var inouts/esi: (payload stmt-var) = [l]
17013     68/push 0/imm32/is-deref:false
17014     68/push 0/imm32/next
17015     68/push 0/imm32/next
17016     52/push-edx/l
17017     68/push 0x11/imm32/alloc-id:fake
17018     68/push 0x11/imm32/alloc-id:fake:payload
17019     89/<- %esi 4/r32/esp
17020     # var inouts = (handle stmt-var) = [var1, var2]
17021     68/push 0/imm32/is-deref:false
17022     56/push-esi/next
17023     68/push 0x11/imm32/alloc-id:fake
17024     51/push-ecx/var1
17025     68/push 0x11/imm32/alloc-id:fake
17026     68/push 0x11/imm32/alloc-id:fake:payload
17027     89/<- %esi 4/r32/esp
17028 $test-add-literal-to-mem:initialize-stmt:
17029     # var stmt/esi: (addr statement)
17030     68/push 0/imm32/next
17031     68/push 0/imm32/next
17032     68/push 0/imm32/outputs
17033     68/push 0/imm32/outputs
17034     56/push-esi/inouts
17035     68/push 0x11/imm32/alloc-id:fake
17036     68/push 0/imm32/operation
17037     68/push 0/imm32/operation
17038     68/push 1/imm32/tag:stmt1
17039     89/<- %esi 4/r32/esp
17040 $test-add-literal-to-mem:initialize-stmt-operation:
17041     # stmt->operation = "add-to"
17042     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17043     (copy-array Heap "add-to" %eax)
17044     # convert
17045     c7 0/subop/copy *Curr-block-depth 0/imm32
17046     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17047     (flush _test-output-buffered-file)
17048 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17054     # check output
17055     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
17056     # . epilogue
17057     89/<- %esp 5/r32/ebp
17058     5d/pop-to-ebp
17059     c3/return
17060 
17061 test-compare-reg-with-reg:
17062     #   compare var1/ecx, var2/eax
17063     # =>
17064     #   39/compare %ecx 0/r32/eax
17065     #
17066     # . prologue
17067     55/push-ebp
17068     89/<- %ebp 4/r32/esp
17069     # setup
17070     (clear-stream _test-output-stream)
17071     (clear-stream $_test-output-buffered-file->buffer)
17072 $test-compare-reg-with-reg:initialize-type:
17073     # var type/ecx: (payload tree type-id) = int
17074     68/push 0/imm32/right:null
17075     68/push 0/imm32/right:null
17076     68/push 0/imm32/left:unused
17077     68/push 1/imm32/value:int
17078     68/push 1/imm32/is-atom?:true
17079     68/push 0x11/imm32/alloc-id:fake:payload
17080     89/<- %ecx 4/r32/esp
17081 $test-compare-reg-with-reg:initialize-var1:
17082     # var var1/ecx: (payload var)
17083     68/push 0/imm32/register
17084     68/push 0/imm32/register
17085     68/push 0/imm32/no-stack-offset
17086     68/push 1/imm32/block-depth
17087     51/push-ecx
17088     68/push 0x11/imm32/alloc-id:fake
17089     68/push 0/imm32/name
17090     68/push 0/imm32/name
17091     68/push 0x11/imm32/alloc-id:fake:payload
17092     89/<- %ecx 4/r32/esp
17093 $test-compare-reg-with-reg:initialize-var1-name:
17094     # var1->name = "var1"
17095     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17096     (copy-array Heap "var1" %eax)
17097 $test-compare-reg-with-reg:initialize-var1-register:
17098     # var1->register = "ecx"
17099     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17100     (copy-array Heap "ecx" %eax)
17101 $test-compare-reg-with-reg:initialize-var2:
17102     # var var2/edx: (payload var)
17103     68/push 0/imm32/register
17104     68/push 0/imm32/register
17105     68/push 0/imm32/no-stack-offset
17106     68/push 1/imm32/block-depth
17107     ff 6/subop/push *(ecx+0x10)
17108     68/push 0x11/imm32/alloc-id:fake
17109     68/push 0/imm32/name
17110     68/push 0/imm32/name
17111     68/push 0x11/imm32/alloc-id:fake:payload
17112     89/<- %edx 4/r32/esp
17113 $test-compare-reg-with-reg:initialize-var2-name:
17114     # var2->name = "var2"
17115     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17116     (copy-array Heap "var2" %eax)
17117 $test-compare-reg-with-reg:initialize-var2-register:
17118     # var2->register = "eax"
17119     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17120     (copy-array Heap "eax" %eax)
17121 $test-compare-reg-with-reg:initialize-inouts:
17122     # var inouts/esi: (payload stmt-var) = [var2]
17123     68/push 0/imm32/is-deref:false
17124     68/push 0/imm32/next
17125     68/push 0/imm32/next
17126     52/push-edx/var2
17127     68/push 0x11/imm32/alloc-id:fake
17128     68/push 0x11/imm32/alloc-id:fake:payload
17129     89/<- %esi 4/r32/esp
17130     # inouts = [var1, var2]
17131     68/push 0/imm32/is-deref:false
17132     56/push-esi/next
17133     68/push 0x11/imm32/alloc-id:fake
17134     51/push-ecx/var1
17135     68/push 0x11/imm32/alloc-id:fake
17136     68/push 0x11/imm32/alloc-id:fake:payload
17137     89/<- %esi 4/r32/esp
17138 $test-compare-reg-with-reg:initialize-stmt:
17139     # var stmt/esi: (addr statement)
17140     68/push 0/imm32/next
17141     68/push 0/imm32/next
17142     68/push 0/imm32/outputs
17143     68/push 0/imm32/outputs
17144     56/push-esi/inouts
17145     68/push 0x11/imm32/alloc-id:fake
17146     68/push 0/imm32/operation
17147     68/push 0/imm32/operation
17148     68/push 1/imm32/tag:stmt1
17149     89/<- %esi 4/r32/esp
17150 $test-compare-reg-with-reg:initialize-stmt-operation:
17151     # stmt->operation = "compare"
17152     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17153     (copy-array Heap "compare" %eax)
17154     # convert
17155     c7 0/subop/copy *Curr-block-depth 0/imm32
17156     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17157     (flush _test-output-buffered-file)
17158 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17164     # check output
17165     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
17166     # . epilogue
17167     89/<- %esp 5/r32/ebp
17168     5d/pop-to-ebp
17169     c3/return
17170 
17171 test-compare-mem-with-reg:
17172     #   compare var1, var2/eax
17173     # =>
17174     #   39/compare *(ebp+___) 0/r32/eax
17175     #
17176     # . prologue
17177     55/push-ebp
17178     89/<- %ebp 4/r32/esp
17179     # setup
17180     (clear-stream _test-output-stream)
17181     (clear-stream $_test-output-buffered-file->buffer)
17182 $test-compare-mem-with-reg:initialize-type:
17183     # var type/ecx: (payload tree type-id) = int
17184     68/push 0/imm32/right:null
17185     68/push 0/imm32/right:null
17186     68/push 0/imm32/left:unused
17187     68/push 1/imm32/value:int
17188     68/push 1/imm32/is-atom?:true
17189     68/push 0x11/imm32/alloc-id:fake:payload
17190     89/<- %ecx 4/r32/esp
17191 $test-compare-mem-with-reg:initialize-var1:
17192     # var var1/ecx: (payload var)
17193     68/push 0/imm32/register
17194     68/push 0/imm32/register
17195     68/push 8/imm32/stack-offset
17196     68/push 1/imm32/block-depth
17197     51/push-ecx
17198     68/push 0x11/imm32/alloc-id:fake
17199     68/push 0/imm32/name
17200     68/push 0/imm32/name
17201     68/push 0x11/imm32/alloc-id:fake:payload
17202     89/<- %ecx 4/r32/esp
17203 $test-compare-mem-with-reg:initialize-var1-name:
17204     # var1->name = "var1"
17205     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17206     (copy-array Heap "var1" %eax)
17207 $test-compare-mem-with-reg:initialize-var2:
17208     # var var2/edx: (payload var)
17209     68/push 0/imm32/register
17210     68/push 0/imm32/register
17211     68/push 0/imm32/no-stack-offset
17212     68/push 1/imm32/block-depth
17213     ff 6/subop/push *(ecx+0x10)
17214     68/push 0x11/imm32/alloc-id:fake
17215     68/push 0/imm32/name
17216     68/push 0/imm32/name
17217     68/push 0x11/imm32/alloc-id:fake:payload
17218     89/<- %edx 4/r32/esp
17219 $test-compare-mem-with-reg:initialize-var2-name:
17220     # var2->name = "var2"
17221     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17222     (copy-array Heap "var2" %eax)
17223 $test-compare-mem-with-reg:initialize-var2-register:
17224     # var2->register = "eax"
17225     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
17226     (copy-array Heap "eax" %eax)
17227 $test-compare-mem-with-reg:initialize-inouts:
17228     # var inouts/esi: (payload stmt-var) = [var2]
17229     68/push 0/imm32/is-deref:false
17230     68/push 0/imm32/next
17231     68/push 0/imm32/next
17232     52/push-edx/var2
17233     68/push 0x11/imm32/alloc-id:fake
17234     68/push 0x11/imm32/alloc-id:fake:payload
17235     89/<- %esi 4/r32/esp
17236     # inouts = [var1, var2]
17237     68/push 0/imm32/is-deref:false
17238     56/push-esi/next
17239     68/push 0x11/imm32/alloc-id:fake
17240     51/push-ecx/var1
17241     68/push 0x11/imm32/alloc-id:fake
17242     68/push 0x11/imm32/alloc-id:fake:payload
17243     89/<- %esi 4/r32/esp
17244 $test-compare-mem-with-reg:initialize-stmt:
17245     # var stmt/esi: (addr statement)
17246     68/push 0/imm32/next
17247     68/push 0/imm32/next
17248     68/push 0/imm32/outputs
17249     68/push 0/imm32/outputs
17250     56/push-esi/inouts
17251     68/push 0x11/imm32/alloc-id:fake
17252     68/push 0/imm32/operation
17253     68/push 0/imm32/operation
17254     68/push 1/imm32/tag:stmt1
17255     89/<- %esi 4/r32/esp
17256 $test-compare-mem-with-reg:initialize-stmt-operation:
17257     # stmt->operation = "compare"
17258     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17259     (copy-array Heap "compare" %eax)
17260     # convert
17261     c7 0/subop/copy *Curr-block-depth 0/imm32
17262     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17263     (flush _test-output-buffered-file)
17264 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17270     # check output
17271     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
17272     # . epilogue
17273     89/<- %esp 5/r32/ebp
17274     5d/pop-to-ebp
17275     c3/return
17276 
17277 test-compare-reg-with-mem:
17278     #   compare var1/eax, var2
17279     # =>
17280     #   3b/compare<- *(ebp+___) 0/r32/eax
17281     #
17282     # . prologue
17283     55/push-ebp
17284     89/<- %ebp 4/r32/esp
17285     # setup
17286     (clear-stream _test-output-stream)
17287     (clear-stream $_test-output-buffered-file->buffer)
17288 $test-compare-reg-with-mem:initialize-type:
17289     # var type/ecx: (payload tree type-id) = int
17290     68/push 0/imm32/right:null
17291     68/push 0/imm32/right:null
17292     68/push 0/imm32/left:unused
17293     68/push 1/imm32/value:int
17294     68/push 1/imm32/is-atom?:true
17295     68/push 0x11/imm32/alloc-id:fake:payload
17296     89/<- %ecx 4/r32/esp
17297 $test-compare-reg-with-mem:initialize-var1:
17298     # var var1/ecx: (payload var)
17299     68/push 0/imm32/register
17300     68/push 0/imm32/register
17301     68/push 0/imm32/no-stack-offset
17302     68/push 1/imm32/block-depth
17303     51/push-ecx
17304     68/push 0x11/imm32/alloc-id:fake
17305     68/push 0/imm32/name
17306     68/push 0/imm32/name
17307     68/push 0x11/imm32/alloc-id:fake:payload
17308     89/<- %ecx 4/r32/esp
17309 $test-compare-reg-with-mem:initialize-var1-name:
17310     # var1->name = "var1"
17311     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17312     (copy-array Heap "var1" %eax)
17313 $test-compare-reg-with-mem:initialize-var1-register:
17314     # var1->register = "eax"
17315     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17316     (copy-array Heap "eax" %eax)
17317 $test-compare-reg-with-mem:initialize-var2:
17318     # var var2/edx: (payload var)
17319     68/push 0/imm32/register
17320     68/push 0/imm32/register
17321     68/push 8/imm32/stack-offset
17322     68/push 1/imm32/block-depth
17323     ff 6/subop/push *(ecx+0x10)
17324     68/push 0x11/imm32/alloc-id:fake
17325     68/push 0/imm32/name
17326     68/push 0/imm32/name
17327     68/push 0x11/imm32/alloc-id:fake:payload
17328     89/<- %edx 4/r32/esp
17329 $test-compare-reg-with-mem:initialize-var2-name:
17330     # var2->name = "var2"
17331     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17332     (copy-array Heap "var2" %eax)
17333 $test-compare-reg-with-mem:initialize-inouts:
17334     # var inouts/esi: (payload stmt-var) = [var2]
17335     68/push 0/imm32/is-deref:false
17336     68/push 0/imm32/next
17337     68/push 0/imm32/next
17338     52/push-edx/var2
17339     68/push 0x11/imm32/alloc-id:fake
17340     68/push 0x11/imm32/alloc-id:fake:payload
17341     89/<- %esi 4/r32/esp
17342     # inouts = [var1, var2]
17343     68/push 0/imm32/is-deref:false
17344     56/push-esi/next
17345     68/push 0x11/imm32/alloc-id:fake
17346     51/push-ecx/var1
17347     68/push 0x11/imm32/alloc-id:fake
17348     68/push 0x11/imm32/alloc-id:fake:payload
17349     89/<- %esi 4/r32/esp
17350 $test-compare-reg-with-mem:initialize-stmt:
17351     # var stmt/esi: (addr statement)
17352     68/push 0/imm32/next
17353     68/push 0/imm32/next
17354     68/push 0/imm32/outputs
17355     68/push 0/imm32/outputs
17356     56/push-esi/inouts
17357     68/push 0x11/imm32/alloc-id:fake
17358     68/push 0/imm32/operation
17359     68/push 0/imm32/operation
17360     68/push 1/imm32/tag:stmt1
17361     89/<- %esi 4/r32/esp
17362 $test-compare-reg-with-mem:initialize-stmt-operation:
17363     # stmt->operation = "compare"
17364     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17365     (copy-array Heap "compare" %eax)
17366     # convert
17367     c7 0/subop/copy *Curr-block-depth 0/imm32
17368     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17369     (flush _test-output-buffered-file)
17370 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17376     # check output
17377     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
17378     # . epilogue
17379     89/<- %esp 5/r32/ebp
17380     5d/pop-to-ebp
17381     c3/return
17382 
17383 test-compare-mem-with-literal:
17384     #   compare var1, 0x34
17385     # =>
17386     #   81 7/subop/compare *(ebp+___) 0x34/imm32
17387     #
17388     # . prologue
17389     55/push-ebp
17390     89/<- %ebp 4/r32/esp
17391     # setup
17392     (clear-stream _test-output-stream)
17393     (clear-stream $_test-output-buffered-file->buffer)
17394 $test-compare-mem-with-literal:initialize-type:
17395     # var type/ecx: (payload tree type-id) = int
17396     68/push 0/imm32/right:null
17397     68/push 0/imm32/right:null
17398     68/push 0/imm32/left:unused
17399     68/push 1/imm32/value:int
17400     68/push 1/imm32/is-atom?:true
17401     68/push 0x11/imm32/alloc-id:fake:payload
17402     89/<- %ecx 4/r32/esp
17403 $test-compare-mem-with-literal:initialize-var1:
17404     # var var1/ecx: (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     51/push-ecx
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/<- %ecx 4/r32/esp
17415 $test-compare-mem-with-literal:initialize-var1-name:
17416     # var1->name = "var1"
17417     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17418     (copy-array Heap "var1" %eax)
17419 $test-compare-mem-with-literal:initialize-literal-type:
17420     # var type/edx: (payload tree type-id) = literal
17421     68/push 0/imm32/right:null
17422     68/push 0/imm32/right:null
17423     68/push 0/imm32/left:unused
17424     68/push 0/imm32/value:literal
17425     68/push 1/imm32/is-atom?:true
17426     68/push 0x11/imm32/alloc-id:fake:payload
17427     89/<- %edx 4/r32/esp
17428 $test-compare-mem-with-literal:initialize-literal:
17429     # var l/edx: (payload var)
17430     68/push 0/imm32/register
17431     68/push 0/imm32/register
17432     68/push 0/imm32/no-stack-offset
17433     68/push 1/imm32/block-depth
17434     52/push-edx
17435     68/push 0x11/imm32/alloc-id:fake
17436     68/push 0/imm32/name
17437     68/push 0/imm32/name
17438     68/push 0x11/imm32/alloc-id:fake:payload
17439     89/<- %edx 4/r32/esp
17440 $test-compare-mem-with-literal:initialize-literal-value:
17441     # l->name = "0x34"
17442     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17443     (copy-array Heap "0x34" %eax)
17444 $test-compare-mem-with-literal:initialize-inouts:
17445     # var inouts/esi: (payload stmt-var) = [l]
17446     68/push 0/imm32/is-deref:false
17447     68/push 0/imm32/next
17448     68/push 0/imm32/next
17449     52/push-edx/l
17450     68/push 0x11/imm32/alloc-id:fake
17451     68/push 0x11/imm32/alloc-id:fake:payload
17452     89/<- %esi 4/r32/esp
17453     # var inouts = (handle stmt-var) = [var1, var2]
17454     68/push 0/imm32/is-deref:false
17455     56/push-esi/next
17456     68/push 0x11/imm32/alloc-id:fake
17457     51/push-ecx/var1
17458     68/push 0x11/imm32/alloc-id:fake
17459     68/push 0x11/imm32/alloc-id:fake:payload
17460     89/<- %esi 4/r32/esp
17461 $test-compare-mem-with-literal:initialize-stmt:
17462     # var stmt/esi: (addr statement)
17463     68/push 0/imm32/next
17464     68/push 0/imm32/next
17465     68/push 0/imm32/outputs
17466     68/push 0/imm32/outputs
17467     56/push-esi/inouts
17468     68/push 0x11/imm32/alloc-id:fake
17469     68/push 0/imm32/operation
17470     68/push 0/imm32/operation
17471     68/push 1/imm32/tag:stmt1
17472     89/<- %esi 4/r32/esp
17473 $test-compare-mem-with-literal:initialize-stmt-operation:
17474     # stmt->operation = "compare"
17475     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17476     (copy-array Heap "compare" %eax)
17477     # convert
17478     c7 0/subop/copy *Curr-block-depth 0/imm32
17479     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17480     (flush _test-output-buffered-file)
17481 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17487     # check output
17488     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
17489     # . epilogue
17490     89/<- %esp 5/r32/ebp
17491     5d/pop-to-ebp
17492     c3/return
17493 
17494 test-compare-eax-with-literal:
17495     #   compare var1/eax 0x34
17496     # =>
17497     #   3d/compare-eax-with 0x34/imm32
17498     #
17499     # . prologue
17500     55/push-ebp
17501     89/<- %ebp 4/r32/esp
17502     # setup
17503     (clear-stream _test-output-stream)
17504     (clear-stream $_test-output-buffered-file->buffer)
17505 $test-compare-eax-with-literal:initialize-type:
17506     # var type/ecx: (payload tree type-id) = int
17507     68/push 0/imm32/right:null
17508     68/push 0/imm32/right:null
17509     68/push 0/imm32/left:unused
17510     68/push 1/imm32/value:int
17511     68/push 1/imm32/is-atom?:true
17512     68/push 0x11/imm32/alloc-id:fake:payload
17513     89/<- %ecx 4/r32/esp
17514 $test-compare-eax-with-literal:initialize-var1:
17515     # var var1/ecx: (payload var)
17516     68/push 0/imm32/register
17517     68/push 0/imm32/register
17518     68/push 0/imm32/no-stack-offset
17519     68/push 1/imm32/block-depth
17520     51/push-ecx
17521     68/push 0x11/imm32/alloc-id:fake
17522     68/push 0/imm32/name
17523     68/push 0/imm32/name
17524     68/push 0x11/imm32/alloc-id:fake:payload
17525     89/<- %ecx 4/r32/esp
17526 $test-compare-eax-with-literal:initialize-var1-name:
17527     # var1->name = "var1"
17528     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17529     (copy-array Heap "var1" %eax)
17530 $test-compare-eax-with-literal:initialize-var1-register:
17531     # v->register = "eax"
17532     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17533     (copy-array Heap "eax" %eax)
17534 $test-compare-eax-with-literal:initialize-literal-type:
17535     # var type/edx: (payload tree type-id) = literal
17536     68/push 0/imm32/right:null
17537     68/push 0/imm32/right:null
17538     68/push 0/imm32/left:unused
17539     68/push 0/imm32/value:literal
17540     68/push 1/imm32/is-atom?:true
17541     68/push 0x11/imm32/alloc-id:fake:payload
17542     89/<- %edx 4/r32/esp
17543 $test-compare-eax-with-literal:initialize-literal:
17544     # var l/edx: (payload var)
17545     68/push 0/imm32/register
17546     68/push 0/imm32/register
17547     68/push 0/imm32/no-stack-offset
17548     68/push 1/imm32/block-depth
17549     52/push-edx
17550     68/push 0x11/imm32/alloc-id:fake
17551     68/push 0/imm32/name
17552     68/push 0/imm32/name
17553     68/push 0x11/imm32/alloc-id:fake:payload
17554     89/<- %edx 4/r32/esp
17555 $test-compare-eax-with-literal:initialize-literal-value:
17556     # l->name = "0x34"
17557     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17558     (copy-array Heap "0x34" %eax)
17559 $test-compare-eax-with-literal:initialize-inouts:
17560     # var inouts/esi: (payload stmt-var) = [l]
17561     68/push 0/imm32/is-deref:false
17562     68/push 0/imm32/next
17563     68/push 0/imm32/next
17564     52/push-edx/l
17565     68/push 0x11/imm32/alloc-id:fake
17566     68/push 0x11/imm32/alloc-id:fake:payload
17567     89/<- %esi 4/r32/esp
17568     # var inouts = (handle stmt-var) = [var1, var2]
17569     68/push 0/imm32/is-deref:false
17570     56/push-esi/next
17571     68/push 0x11/imm32/alloc-id:fake
17572     51/push-ecx/var1
17573     68/push 0x11/imm32/alloc-id:fake
17574     68/push 0x11/imm32/alloc-id:fake:payload
17575     89/<- %esi 4/r32/esp
17576 $test-compare-eax-with-literal:initialize-stmt:
17577     # var stmt/esi: (addr statement)
17578     68/push 0/imm32/next
17579     68/push 0/imm32/next
17580     68/push 0/imm32/outputs
17581     68/push 0/imm32/outputs
17582     56/push-esi/inouts
17583     68/push 0x11/imm32/alloc-id:fake
17584     68/push 0/imm32/operation
17585     68/push 0/imm32/operation
17586     68/push 1/imm32/tag:stmt1
17587     89/<- %esi 4/r32/esp
17588 $test-compare-eax-with-literal:initialize-stmt-operation:
17589     # stmt->operation = "compare"
17590     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17591     (copy-array Heap "compare" %eax)
17592     # convert
17593     c7 0/subop/copy *Curr-block-depth 0/imm32
17594     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17595     (flush _test-output-buffered-file)
17596 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17602     # check output
17603     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
17604     # . epilogue
17605     89/<- %esp 5/r32/ebp
17606     5d/pop-to-ebp
17607     c3/return
17608 
17609 test-compare-reg-with-literal:
17610     #   compare var1/ecx 0x34
17611     # =>
17612     #   81 7/subop/compare %ecx 0x34/imm32
17613     #
17614     # . prologue
17615     55/push-ebp
17616     89/<- %ebp 4/r32/esp
17617     # setup
17618     (clear-stream _test-output-stream)
17619     (clear-stream $_test-output-buffered-file->buffer)
17620 $test-compare-reg-with-literal:initialize-type:
17621     # var type/ecx: (payload tree type-id) = int
17622     68/push 0/imm32/right:null
17623     68/push 0/imm32/right:null
17624     68/push 0/imm32/left:unused
17625     68/push 1/imm32/value:int
17626     68/push 1/imm32/is-atom?:true
17627     68/push 0x11/imm32/alloc-id:fake:payload
17628     89/<- %ecx 4/r32/esp
17629 $test-compare-reg-with-literal:initialize-var1:
17630     # var var1/ecx: (payload var)
17631     68/push 0/imm32/register
17632     68/push 0/imm32/register
17633     68/push 0/imm32/no-stack-offset
17634     68/push 1/imm32/block-depth
17635     51/push-ecx
17636     68/push 0x11/imm32/alloc-id:fake
17637     68/push 0/imm32/name
17638     68/push 0/imm32/name
17639     68/push 0x11/imm32/alloc-id:fake:payload
17640     89/<- %ecx 4/r32/esp
17641 $test-compare-reg-with-literal:initialize-var1-name:
17642     # var1->name = "var1"
17643     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17644     (copy-array Heap "var1" %eax)
17645 $test-compare-reg-with-literal:initialize-var1-register:
17646     # v->register = "ecx"
17647     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
17648     (copy-array Heap "ecx" %eax)
17649 $test-compare-reg-with-literal:initialize-literal-type:
17650     # var type/edx: (payload tree type-id) = literal
17651     68/push 0/imm32/right:null
17652     68/push 0/imm32/right:null
17653     68/push 0/imm32/left:unused
17654     68/push 0/imm32/value:literal
17655     68/push 1/imm32/is-atom?:true
17656     68/push 0x11/imm32/alloc-id:fake:payload
17657     89/<- %edx 4/r32/esp
17658 $test-compare-reg-with-literal:initialize-literal:
17659     # var l/edx: (payload var)
17660     68/push 0/imm32/register
17661     68/push 0/imm32/register
17662     68/push 0/imm32/no-stack-offset
17663     68/push 1/imm32/block-depth
17664     52/push-edx
17665     68/push 0x11/imm32/alloc-id:fake
17666     68/push 0/imm32/name
17667     68/push 0/imm32/name
17668     68/push 0x11/imm32/alloc-id:fake:payload
17669     89/<- %edx 4/r32/esp
17670 $test-compare-reg-with-literal:initialize-literal-value:
17671     # l->name = "0x34"
17672     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
17673     (copy-array Heap "0x34" %eax)
17674 $test-compare-reg-with-literal:initialize-inouts:
17675     # var inouts/esi: (payload stmt-var) = [l]
17676     68/push 0/imm32/is-deref:false
17677     68/push 0/imm32/next
17678     68/push 0/imm32/next
17679     52/push-edx/l
17680     68/push 0x11/imm32/alloc-id:fake
17681     68/push 0x11/imm32/alloc-id:fake:payload
17682     89/<- %esi 4/r32/esp
17683     # var inouts = (handle stmt-var) = [var1, var2]
17684     68/push 0/imm32/is-deref:false
17685     56/push-esi/next
17686     68/push 0x11/imm32/alloc-id:fake
17687     51/push-ecx/var1
17688     68/push 0x11/imm32/alloc-id:fake
17689     68/push 0x11/imm32/alloc-id:fake:payload
17690     89/<- %esi 4/r32/esp
17691 $test-compare-reg-with-literal:initialize-stmt:
17692     # var stmt/esi: (addr statement)
17693     68/push 0/imm32/next
17694     68/push 0/imm32/next
17695     68/push 0/imm32/outputs
17696     68/push 0/imm32/outputs
17697     56/push-esi/inouts
17698     68/push 0x11/imm32/alloc-id:fake
17699     68/push 0/imm32/operation
17700     68/push 0/imm32/operation
17701     68/push 1/imm32/tag:stmt1
17702     89/<- %esi 4/r32/esp
17703 $test-compare-reg-with-literal:initialize-stmt-operation:
17704     # stmt->operation = "compare"
17705     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17706     (copy-array Heap "compare" %eax)
17707     # convert
17708     c7 0/subop/copy *Curr-block-depth 0/imm32
17709     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
17710     (flush _test-output-buffered-file)
17711 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17717     # check output
17718     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
17719     # . epilogue
17720     89/<- %esp 5/r32/ebp
17721     5d/pop-to-ebp
17722     c3/return
17723 
17724 test-emit-subx-stmt-function-call:
17725     # Call a function on a variable on the stack.
17726     #   f foo
17727     # =>
17728     #   (f *(ebp-8))
17729     # (Changing the function name supports overloading in general, but here it
17730     # just serves to help disambiguate things.)
17731     #
17732     # There's a variable on the var stack as follows:
17733     #   name: 'foo'
17734     #   type: int
17735     #   stack-offset: -8
17736     #
17737     # There's nothing in primitives.
17738     #
17739     # We don't perform any checking here on the type of 'f'.
17740     #
17741     # . prologue
17742     55/push-ebp
17743     89/<- %ebp 4/r32/esp
17744     # setup
17745     (clear-stream _test-output-stream)
17746     (clear-stream $_test-output-buffered-file->buffer)
17747 $test-emit-subx-function-call:initialize-type:
17748     # var type/ecx: (payload tree type-id) = int
17749     68/push 0/imm32/right:null
17750     68/push 0/imm32/right:null
17751     68/push 0/imm32/left:unused
17752     68/push 1/imm32/value:int
17753     68/push 1/imm32/is-atom?:true
17754     68/push 0x11/imm32/alloc-id:fake:payload
17755     89/<- %ecx 4/r32/esp
17756 $test-emit-subx-function-call:initialize-var:
17757     # var var-foo/ecx: (payload var) = var(type)
17758     68/push 0/imm32/no-register
17759     68/push 0/imm32/no-register
17760     68/push -8/imm32/stack-offset
17761     68/push 1/imm32/block-depth
17762     51/push-ecx/type
17763     68/push 0x11/imm32/alloc-id:fake
17764     68/push 0/imm32/name
17765     68/push 0/imm32/name
17766     68/push 0x11/imm32/alloc-id:fake:payload
17767     89/<- %ecx 4/r32/esp
17768 $test-emit-subx-function-call:initialize-var-name:
17769     # var-foo->name = "foo"
17770     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17771     (copy-array Heap "foo" %eax)
17772 $test-emit-subx-function-call:initialize-stmt-var:
17773     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
17774     68/push 0/imm32/is-deref:false
17775     68/push 0/imm32/next
17776     68/push 0/imm32/next
17777     51/push-ecx/var-foo
17778     68/push 0x11/imm32/alloc-id:fake
17779     68/push 0x11/imm32/alloc-id:fake:payload
17780     89/<- %ebx 4/r32/esp
17781 $test-emit-subx-function-call:initialize-stmt:
17782     # var stmt/esi: (addr statement)
17783     68/push 0/imm32/no-outputs
17784     68/push 0/imm32/no-outputs
17785     53/push-ebx/inouts
17786     68/push 0x11/imm32/alloc-id:fake
17787     68/push 0/imm32/operation
17788     68/push 0/imm32/operation
17789     68/push 1/imm32/tag
17790     89/<- %esi 4/r32/esp
17791 $test-emit-subx-function-call:initialize-stmt-operation:
17792     # stmt->operation = "f"
17793     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17794     (copy-array Heap "f" %eax)
17795     # convert
17796     c7 0/subop/copy *Curr-block-depth 0/imm32
17797     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
17798     (flush _test-output-buffered-file)
17799 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17805     # check output
17806     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
17807     # . epilogue
17808     89/<- %esp 5/r32/ebp
17809     5d/pop-to-ebp
17810     c3/return
17811 
17812 test-emit-subx-stmt-function-call-with-literal-arg:
17813     # Call a function on a literal.
17814     #   f 0x34
17815     # =>
17816     #   (f2 0x34)
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-emit-subx-function-call-with-literal-arg: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 0/imm32/value:literal
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-emit-subx-function-call-with-literal-arg:initialize-var:
17834     # var var-foo/ecx: (payload var) = var(lit)
17835     68/push 0/imm32/no-register
17836     68/push 0/imm32/no-register
17837     68/push 0/imm32/no-stack-offset
17838     68/push 1/imm32/block-depth
17839     51/push-ecx/type
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-emit-subx-function-call-with-literal-arg:initialize-var-name:
17846     # var-foo->name = "0x34"
17847     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
17848     (copy-array Heap "0x34" %eax)
17849 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
17850     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
17851     68/push 0/imm32/is-deref:false
17852     68/push 0/imm32/next
17853     68/push 0/imm32/next
17854     51/push-ecx/var-foo
17855     68/push 0x11/imm32/alloc-id:fake
17856     68/push 0x11/imm32/alloc-id:fake:payload
17857     89/<- %ebx 4/r32/esp
17858 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
17859     # var stmt/esi: (addr statement)
17860     68/push 0/imm32/no-outputs
17861     68/push 0/imm32/no-outputs
17862     53/push-ebx/inouts
17863     68/push 0x11/imm32/alloc-id:fake
17864     68/push 0/imm32/operation
17865     68/push 0/imm32/operation
17866     68/push 1/imm32/tag
17867     89/<- %esi 4/r32/esp
17868 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
17869     # stmt->operation = "f"
17870     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
17871     (copy-array Heap "f" %eax)
17872     # convert
17873     c7 0/subop/copy *Curr-block-depth 0/imm32
17874     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
17875     (flush _test-output-buffered-file)
17876 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
17882     # check output
17883     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
17884     # . epilogue
17885     89/<- %esp 5/r32/ebp
17886     5d/pop-to-ebp
17887     c3/return
17888 
17889 emit-indent:  # out: (addr buffered-file), n: int
17890     # . prologue
17891     55/push-ebp
17892     89/<- %ebp 4/r32/esp
17893     # . save registers
17894     50/push-eax
17895     # var i/eax: int = n
17896     8b/-> *(ebp+0xc) 0/r32/eax
17897     {
17898       # if (i <= 0) break
17899       3d/compare-eax-with 0/imm32
17900       7e/jump-if-<= break/disp8
17901       (write-buffered *(ebp+8) "  ")
17902       48/decrement-eax
17903       eb/jump loop/disp8
17904     }
17905 $emit-indent:end:
17906     # . restore registers
17907     58/pop-to-eax
17908     # . epilogue
17909     89/<- %esp 5/r32/ebp
17910     5d/pop-to-ebp
17911     c3/return
17912 
17913 emit-subx-prologue:  # out: (addr buffered-file)
17914     # . prologue
17915     55/push-ebp
17916     89/<- %ebp 4/r32/esp
17917     #
17918     (write-buffered *(ebp+8) "  # . prologue\n")
17919     (write-buffered *(ebp+8) "  55/push-ebp\n")
17920     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
17921 $emit-subx-prologue:end:
17922     # . epilogue
17923     89/<- %esp 5/r32/ebp
17924     5d/pop-to-ebp
17925     c3/return
17926 
17927 emit-subx-epilogue:  # out: (addr buffered-file)
17928     # . prologue
17929     55/push-ebp
17930     89/<- %ebp 4/r32/esp
17931     #
17932     (write-buffered *(ebp+8) "  # . epilogue\n")
17933     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
17934     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
17935     (write-buffered *(ebp+8) "  c3/return\n")
17936 $emit-subx-epilogue:end:
17937     # . epilogue
17938     89/<- %esp 5/r32/ebp
17939     5d/pop-to-ebp
17940     c3/return