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 # However, there's no need for singletons, so we can assume (int) == int
  369 #   - if x->right == nil, x is an atom
  370 #   - x->left contains either a pointer to a pair, or an atomic type-id directly.
  371 
  372 Tree-is-atom:  # boolean
  373   0/imm32
  374 # if left-is-atom?
  375 Tree-value:  # type-id
  376   4/imm32
  377 # unless left-is-atom?
  378 Tree-left:  # (addr tree type-id)
  379   4/imm32
  380 Tree-right:  # (addr tree type-id)
  381   0xc/imm32
  382 #
  383 Tree-size:  # (addr int)
  384   0x14/imm32
  385 
  386 # Types
  387 
  388 # TODO: heap allocations here can't be reclaimed
  389 Type-id:  # (stream (addr array byte))
  390   0x1c/imm32/write
  391   0/imm32/read
  392   0x100/imm32/size
  393   # data
  394   "literal"/imm32  # 0: value is just the name
  395   "int"/imm32  # 1
  396   "addr"/imm32  # 2
  397   "array"/imm32  # 3
  398   "handle"/imm32  # 4
  399   "boolean"/imm32  # 5
  400   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  401   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  402   0/imm32
  403   # 0x20
  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   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  409   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  410   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  411 
  412 # == Type definitions
  413 # Program->types contains some typeinfo for each type definition.
  414 # Types contain vars with types, but can't specify registers.
  415 Typeinfo-id:  # type-id
  416   0/imm32
  417 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  418   4/imm32
  419 # Total size must be >= 0
  420 # During parsing it may take on two additional values:
  421 #   -2: not yet initialized
  422 #   -1: in process of being computed
  423 # See populate-mu-type-sizes for details.
  424 Typeinfo-total-size-in-bytes:  # int
  425   0xc/imm32
  426 Typeinfo-next:  # (handle typeinfo)
  427   0x10/imm32
  428 Typeinfo-size:  # (addr int)
  429   0x18/imm32
  430 
  431 # Each entry in the typeinfo->fields table has a pointer to a string and a
  432 # pointer to a typeinfo-entry.
  433 Typeinfo-fields-row-size:  # (addr int)
  434   0x10/imm32
  435 
  436 # typeinfo-entry objects have information about a field in a single record type
  437 #
  438 # each field of a type is represented using two var's:
  439 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  440 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  441 # computing the output happens after parsing; in the meantime we preserve the
  442 # order of fields in the 'index' field.
  443 Typeinfo-entry-input-var:  # (handle var)
  444   0/imm32
  445 Typeinfo-entry-index:  # int
  446   8/imm32
  447 Typeinfo-entry-output-var:  # (handle var)
  448   0xc/imm32
  449 Typeinfo-entry-size:  # (addr int)
  450   0x14/imm32
  451 
  452 == code
  453 
  454 Entry:
  455     # . prologue
  456     89/<- %ebp 4/r32/esp
  457     (new-segment *Heap-size Heap)
  458     # if (argv[1] == "test') run-tests()
  459     {
  460       # if (argc <= 1) break
  461       81 7/subop/compare *ebp 1/imm32
  462       7e/jump-if-<= break/disp8
  463       # if (argv[1] != "test") break
  464       (kernel-string-equal? *(ebp+8) "test")  # => eax
  465       3d/compare-eax-and 0/imm32/false
  466       74/jump-if-= break/disp8
  467       #
  468       (run-tests)
  469       # syscall(exit, *Num-test-failures)
  470       8b/-> *Num-test-failures 3/r32/ebx
  471       eb/jump $mu-main:end/disp8
  472     }
  473     # otherwise convert Stdin
  474     (convert-mu Stdin Stdout)
  475     (flush Stdout)
  476     # syscall(exit, 0)
  477     bb/copy-to-ebx 0/imm32
  478 $mu-main:end:
  479     b8/copy-to-eax 1/imm32/exit
  480     cd/syscall 0x80/imm8
  481 
  482 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file)
  483     # . prologue
  484     55/push-ebp
  485     89/<- %ebp 4/r32/esp
  486     # initialize global data structures
  487     c7 0/subop/copy *Next-block-index 1/imm32
  488     c7 0/subop/copy *Type-id 0x1c/imm32  # stream-write
  489     c7 0/subop/copy *_Program-functions 0/imm32
  490     c7 0/subop/copy *_Program-functions->payload 0/imm32
  491     c7 0/subop/copy *_Program-types 0/imm32
  492     c7 0/subop/copy *_Program-types->payload 0/imm32
  493     #
  494     (parse-mu *(ebp+8))
  495     (populate-mu-type-sizes)
  496 #?     (dump-typeinfos "=== typeinfos\n")
  497     (check-mu-types)
  498     (emit-subx *(ebp+0xc))
  499 $convert-mu:end:
  500     # . epilogue
  501     89/<- %esp 5/r32/ebp
  502     5d/pop-to-ebp
  503     c3/return
  504 
  505 test-convert-empty-input:
  506     # empty input => empty output
  507     # . prologue
  508     55/push-ebp
  509     89/<- %ebp 4/r32/esp
  510     # setup
  511     (clear-stream _test-input-stream)
  512     (clear-stream $_test-input-buffered-file->buffer)
  513     (clear-stream _test-output-stream)
  514     (clear-stream $_test-output-buffered-file->buffer)
  515     #
  516     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  517     (flush _test-output-buffered-file)
  518     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  519     # . epilogue
  520     89/<- %esp 5/r32/ebp
  521     5d/pop-to-ebp
  522     c3/return
  523 
  524 test-convert-function-skeleton:
  525     # . prologue
  526     55/push-ebp
  527     89/<- %ebp 4/r32/esp
  528     # setup
  529     (clear-stream _test-input-stream)
  530     (clear-stream $_test-input-buffered-file->buffer)
  531     (clear-stream _test-output-stream)
  532     (clear-stream $_test-output-buffered-file->buffer)
  533     #
  534     (write _test-input-stream "fn foo {\n")
  535     (write _test-input-stream "}\n")
  536     # convert
  537     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  538     (flush _test-output-buffered-file)
  539 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  545     # check output
  546     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  547     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  548     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  549     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  550     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  551     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  552     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  553     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  554     # . epilogue
  555     89/<- %esp 5/r32/ebp
  556     5d/pop-to-ebp
  557     c3/return
  558 
  559 test-convert-multiple-function-skeletons:
  560     # . prologue
  561     55/push-ebp
  562     89/<- %ebp 4/r32/esp
  563     # setup
  564     (clear-stream _test-input-stream)
  565     (clear-stream $_test-input-buffered-file->buffer)
  566     (clear-stream _test-output-stream)
  567     (clear-stream $_test-output-buffered-file->buffer)
  568     #
  569     (write _test-input-stream "fn foo {\n")
  570     (write _test-input-stream "}\n")
  571     (write _test-input-stream "fn bar {\n")
  572     (write _test-input-stream "}\n")
  573     # convert
  574     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  575     (flush _test-output-buffered-file)
  576 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  582     # check first function
  583     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  584     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  585     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  586     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  587     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  588     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  589     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  590     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  591     # check second function
  592     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  593     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  594     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  595     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  596     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  597     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  598     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  599     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  600     # . epilogue
  601     89/<- %esp 5/r32/ebp
  602     5d/pop-to-ebp
  603     c3/return
  604 
  605 test-convert-function-with-arg:
  606     # . prologue
  607     55/push-ebp
  608     89/<- %ebp 4/r32/esp
  609     # setup
  610     (clear-stream _test-input-stream)
  611     (clear-stream $_test-input-buffered-file->buffer)
  612     (clear-stream _test-output-stream)
  613     (clear-stream $_test-output-buffered-file->buffer)
  614     #
  615     (write _test-input-stream "fn foo n: int {\n")
  616     (write _test-input-stream "}\n")
  617     # convert
  618     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  619     (flush _test-output-buffered-file)
  620 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  626     # check output
  627     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  628     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  629     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  630     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  631     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  632     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  633     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  634     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  635     # . epilogue
  636     89/<- %esp 5/r32/ebp
  637     5d/pop-to-ebp
  638     c3/return
  639 
  640 test-convert-function-with-arg-and-body:
  641     # . prologue
  642     55/push-ebp
  643     89/<- %ebp 4/r32/esp
  644     # setup
  645     (clear-stream _test-input-stream)
  646     (clear-stream $_test-input-buffered-file->buffer)
  647     (clear-stream _test-output-stream)
  648     (clear-stream $_test-output-buffered-file->buffer)
  649     #
  650     (write _test-input-stream "fn foo n: int {\n")
  651     (write _test-input-stream "  increment n\n")
  652     (write _test-input-stream "}\n")
  653     # convert
  654     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  655     (flush _test-output-buffered-file)
  656 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  662     # check output
  663     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  664     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  665     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  666     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  667     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  668     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  669     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  670     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  671     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  672     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  673     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  674     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  675     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  676     # . epilogue
  677     89/<- %esp 5/r32/ebp
  678     5d/pop-to-ebp
  679     c3/return
  680 
  681 test-convert-function-distinguishes-args:
  682     # . prologue
  683     55/push-ebp
  684     89/<- %ebp 4/r32/esp
  685     # setup
  686     (clear-stream _test-input-stream)
  687     (clear-stream $_test-input-buffered-file->buffer)
  688     (clear-stream _test-output-stream)
  689     (clear-stream $_test-output-buffered-file->buffer)
  690     #
  691     (write _test-input-stream "fn foo a: int, b: int {\n")
  692     (write _test-input-stream "  increment b\n")
  693     (write _test-input-stream "}\n")
  694     # convert
  695     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  696     (flush _test-output-buffered-file)
  697 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  703     # check output
  704     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  705     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  706     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  707     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  708     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  709     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  710     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  711     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  712     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  713     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  714     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  715     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  716     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  717     # . epilogue
  718     89/<- %esp 5/r32/ebp
  719     5d/pop-to-ebp
  720     c3/return
  721 
  722 test-convert-function-returns-result:
  723     # . prologue
  724     55/push-ebp
  725     89/<- %ebp 4/r32/esp
  726     # setup
  727     (clear-stream _test-input-stream)
  728     (clear-stream $_test-input-buffered-file->buffer)
  729     (clear-stream _test-output-stream)
  730     (clear-stream $_test-output-buffered-file->buffer)
  731     #
  732     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  733     (write _test-input-stream "  result <- copy a\n")
  734     (write _test-input-stream "  result <- increment\n")
  735     (write _test-input-stream "}\n")
  736     # convert
  737     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  738     (flush _test-output-buffered-file)
  739 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  745     # check output
  746     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  747     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  748     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  749     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  750     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  751     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  752     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  753     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  754     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  755     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  756     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  757     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  758     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  759     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  760     # . epilogue
  761     89/<- %esp 5/r32/ebp
  762     5d/pop-to-ebp
  763     c3/return
  764 
  765 test-convert-function-with-literal-arg:
  766     # . prologue
  767     55/push-ebp
  768     89/<- %ebp 4/r32/esp
  769     # setup
  770     (clear-stream _test-input-stream)
  771     (clear-stream $_test-input-buffered-file->buffer)
  772     (clear-stream _test-output-stream)
  773     (clear-stream $_test-output-buffered-file->buffer)
  774     #
  775     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  776     (write _test-input-stream "  result <- copy a\n")
  777     (write _test-input-stream "  result <- add 1\n")
  778     (write _test-input-stream "}\n")
  779     # convert
  780     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  781     (flush _test-output-buffered-file)
  782 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  788     # check output
  789     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  790     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  791     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  792     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  793     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  794     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  795     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  796     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  797     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  798     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  799     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  800     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  801     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  802     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  803     # . epilogue
  804     89/<- %esp 5/r32/ebp
  805     5d/pop-to-ebp
  806     c3/return
  807 
  808 test-convert-function-with-literal-arg-2:
  809     # . prologue
  810     55/push-ebp
  811     89/<- %ebp 4/r32/esp
  812     # setup
  813     (clear-stream _test-input-stream)
  814     (clear-stream $_test-input-buffered-file->buffer)
  815     (clear-stream _test-output-stream)
  816     (clear-stream $_test-output-buffered-file->buffer)
  817     #
  818     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  819     (write _test-input-stream "  result <- copy a\n")
  820     (write _test-input-stream "  result <- add 1\n")
  821     (write _test-input-stream "}\n")
  822     # convert
  823     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  824     (flush _test-output-buffered-file)
  825 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  831     # check output
  832     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  833     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  834     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  835     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  836     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  837     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  838     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  839     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  840     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  841     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  842     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  843     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  844     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  845     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  846     # . epilogue
  847     89/<- %esp 5/r32/ebp
  848     5d/pop-to-ebp
  849     c3/return
  850 
  851 test-convert-function-call-with-literal-arg:
  852     # . prologue
  853     55/push-ebp
  854     89/<- %ebp 4/r32/esp
  855     # setup
  856     (clear-stream _test-input-stream)
  857     (clear-stream $_test-input-buffered-file->buffer)
  858     (clear-stream _test-output-stream)
  859     (clear-stream $_test-output-buffered-file->buffer)
  860     #
  861     (write _test-input-stream "fn main -> result/ebx: int {\n")
  862     (write _test-input-stream "  result <- do-add 3 4\n")
  863     (write _test-input-stream "}\n")
  864     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  865     (write _test-input-stream "  result <- copy a\n")
  866     (write _test-input-stream "  result <- add b\n")
  867     (write _test-input-stream "}\n")
  868     # convert
  869     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  870     (flush _test-output-buffered-file)
  871 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  877     # check output
  878     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  879     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  880     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  881     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  882     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  883     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  884     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  885     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  886     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  887     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  888     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  889     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  890     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  891     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  892     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  893     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  894     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  895     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  896     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  897     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  898     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  899     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  900     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  901     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  902     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  903     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  904     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  905     # . epilogue
  906     89/<- %esp 5/r32/ebp
  907     5d/pop-to-ebp
  908     c3/return
  909 
  910 test-convert-function-with-local-var-in-mem:
  911     # . prologue
  912     55/push-ebp
  913     89/<- %ebp 4/r32/esp
  914     # setup
  915     (clear-stream _test-input-stream)
  916     (clear-stream $_test-input-buffered-file->buffer)
  917     (clear-stream _test-output-stream)
  918     (clear-stream $_test-output-buffered-file->buffer)
  919     #
  920     (write _test-input-stream "fn foo {\n")
  921     (write _test-input-stream "  var x: int\n")
  922     (write _test-input-stream "  increment x\n")
  923     (write _test-input-stream "}\n")
  924     # convert
  925     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  926     (flush _test-output-buffered-file)
  927 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  933     # check output
  934     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  935     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  936     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  937     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  938     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  939     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  940     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  941     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  942     (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")
  943     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  944     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  945     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  946     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  947     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  948     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  949     # . epilogue
  950     89/<- %esp 5/r32/ebp
  951     5d/pop-to-ebp
  952     c3/return
  953 
  954 test-convert-function-with-local-var-with-compound-type-in-mem:
  955     # . prologue
  956     55/push-ebp
  957     89/<- %ebp 4/r32/esp
  958     # setup
  959     (clear-stream _test-input-stream)
  960     (clear-stream $_test-input-buffered-file->buffer)
  961     (clear-stream _test-output-stream)
  962     (clear-stream $_test-output-buffered-file->buffer)
  963     #
  964     (write _test-input-stream "fn foo {\n")
  965     (write _test-input-stream "  var x: (addr int)\n")
  966     (write _test-input-stream "  copy-to x, 0\n")
  967     (write _test-input-stream "}\n")
  968     # convert
  969     (convert-mu _test-input-buffered-file _test-output-buffered-file)
  970     (flush _test-output-buffered-file)
  971 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
  977     # check output
  978     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
  979     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
  980     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
  981     (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")
  982     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
  983     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
  984     (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")
  985     (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")
  986     (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")
  987     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
  988     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
  989     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
  990     (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")
  991     (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")
  992     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
  993     # . epilogue
  994     89/<- %esp 5/r32/ebp
  995     5d/pop-to-ebp
  996     c3/return
  997 
  998 test-convert-function-with-local-var-in-reg:
  999     # . prologue
 1000     55/push-ebp
 1001     89/<- %ebp 4/r32/esp
 1002     # setup
 1003     (clear-stream _test-input-stream)
 1004     (clear-stream $_test-input-buffered-file->buffer)
 1005     (clear-stream _test-output-stream)
 1006     (clear-stream $_test-output-buffered-file->buffer)
 1007     #
 1008     (write _test-input-stream "fn foo {\n")
 1009     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1010     (write _test-input-stream "  x <- increment\n")
 1011     (write _test-input-stream "}\n")
 1012     # convert
 1013     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1014     (flush _test-output-buffered-file)
 1015 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1021     # check output
 1022     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1023     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1024     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1025     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1026     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1027     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1028     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1029     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1030     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1031     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1032     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1033     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1034     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1035     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1036     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1037     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1038     # . epilogue
 1039     89/<- %esp 5/r32/ebp
 1040     5d/pop-to-ebp
 1041     c3/return
 1042 
 1043 test-convert-function-with-second-local-var-in-same-reg:
 1044     # . prologue
 1045     55/push-ebp
 1046     89/<- %ebp 4/r32/esp
 1047     # setup
 1048     (clear-stream _test-input-stream)
 1049     (clear-stream $_test-input-buffered-file->buffer)
 1050     (clear-stream _test-output-stream)
 1051     (clear-stream $_test-output-buffered-file->buffer)
 1052     #
 1053     (write _test-input-stream "fn foo {\n")
 1054     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1055     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1056     (write _test-input-stream "  y <- increment\n")
 1057     (write _test-input-stream "}\n")
 1058     # convert
 1059     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1060     (flush _test-output-buffered-file)
 1061 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1067     # check output
 1068     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1069     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1070     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1071     (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")
 1072     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1073     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1074     (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")
 1075     (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")
 1076     (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")
 1077     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1078     (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")
 1079     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1080     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1081     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1082     (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")
 1083     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1084     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1085     # . epilogue
 1086     89/<- %esp 5/r32/ebp
 1087     5d/pop-to-ebp
 1088     c3/return
 1089 
 1090 test-convert-function-with-local-var-dereferenced:
 1091     # . prologue
 1092     55/push-ebp
 1093     89/<- %ebp 4/r32/esp
 1094     # setup
 1095     (clear-stream _test-input-stream)
 1096     (clear-stream $_test-input-buffered-file->buffer)
 1097     (clear-stream _test-output-stream)
 1098     (clear-stream $_test-output-buffered-file->buffer)
 1099     #
 1100     (write _test-input-stream "fn foo {\n")
 1101     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1102     (write _test-input-stream "  increment *x\n")
 1103     (write _test-input-stream "}\n")
 1104     # convert
 1105     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1106     (flush _test-output-buffered-file)
 1107 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1113     # check output
 1114     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1115     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1116     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1117     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1118     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1120     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1121     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1122     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1123     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1124     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1125     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1126     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1127     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1128     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1129     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1130     # . epilogue
 1131     89/<- %esp 5/r32/ebp
 1132     5d/pop-to-ebp
 1133     c3/return
 1134 
 1135 test-convert-compare-register-with-literal:
 1136     # . prologue
 1137     55/push-ebp
 1138     89/<- %ebp 4/r32/esp
 1139     # setup
 1140     (clear-stream _test-input-stream)
 1141     (clear-stream $_test-input-buffered-file->buffer)
 1142     (clear-stream _test-output-stream)
 1143     (clear-stream $_test-output-buffered-file->buffer)
 1144     #
 1145     (write _test-input-stream "fn foo {\n")
 1146     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1147     (write _test-input-stream "  compare x, 0\n")
 1148     (write _test-input-stream "}\n")
 1149     # convert
 1150     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1151     (flush _test-output-buffered-file)
 1152 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1158     # check output
 1159     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1160     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1161     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1162     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1163     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1164     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1165     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1166     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1167     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1168     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1169     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1170     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1171     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1172     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1173     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1174     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1175     # . epilogue
 1176     89/<- %esp 5/r32/ebp
 1177     5d/pop-to-ebp
 1178     c3/return
 1179 
 1180 test-convert-function-with-local-var-in-block:
 1181     # . prologue
 1182     55/push-ebp
 1183     89/<- %ebp 4/r32/esp
 1184     # setup
 1185     (clear-stream _test-input-stream)
 1186     (clear-stream $_test-input-buffered-file->buffer)
 1187     (clear-stream _test-output-stream)
 1188     (clear-stream $_test-output-buffered-file->buffer)
 1189     #
 1190     (write _test-input-stream "fn foo {\n")
 1191     (write _test-input-stream "  {\n")
 1192     (write _test-input-stream "    var x: int\n")
 1193     (write _test-input-stream "    increment x\n")
 1194     (write _test-input-stream "  }\n")
 1195     (write _test-input-stream "}\n")
 1196     # convert
 1197     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1198     (flush _test-output-buffered-file)
 1199 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1205     # check output
 1206     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1207     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1208     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1209     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1210     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1211     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1212     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1213     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1214     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1215     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1216     (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")
 1217     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1219     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1221     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1222     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1223     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1224     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1225     # . epilogue
 1226     89/<- %esp 5/r32/ebp
 1227     5d/pop-to-ebp
 1228     c3/return
 1229 
 1230 test-convert-function-with-local-var-in-named-block:
 1231     # . prologue
 1232     55/push-ebp
 1233     89/<- %ebp 4/r32/esp
 1234     # setup
 1235     (clear-stream _test-input-stream)
 1236     (clear-stream $_test-input-buffered-file->buffer)
 1237     (clear-stream _test-output-stream)
 1238     (clear-stream $_test-output-buffered-file->buffer)
 1239     #
 1240     (write _test-input-stream "fn foo {\n")
 1241     (write _test-input-stream "  $bar: {\n")
 1242     (write _test-input-stream "    var x: int\n")
 1243     (write _test-input-stream "    increment x\n")
 1244     (write _test-input-stream "  }\n")
 1245     (write _test-input-stream "}\n")
 1246     # convert
 1247     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1248     (flush _test-output-buffered-file)
 1249 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1255     # check output
 1256     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1257     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1258     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1259     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1260     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1261     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1262     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1263     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1264     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1265     (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")
 1266     (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")
 1267     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1268     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1269     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1270     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1271     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1272     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1273     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1274     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1275     # . epilogue
 1276     89/<- %esp 5/r32/ebp
 1277     5d/pop-to-ebp
 1278     c3/return
 1279 
 1280 test-always-shadow-outermost-reg-vars-in-function:
 1281     # . prologue
 1282     55/push-ebp
 1283     89/<- %ebp 4/r32/esp
 1284     # setup
 1285     (clear-stream _test-input-stream)
 1286     (clear-stream $_test-input-buffered-file->buffer)
 1287     (clear-stream _test-output-stream)
 1288     (clear-stream $_test-output-buffered-file->buffer)
 1289     #
 1290     (write _test-input-stream "fn foo {\n")
 1291     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1292     (write _test-input-stream "}\n")
 1293     # convert
 1294     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1295     (flush _test-output-buffered-file)
 1296 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1302     # check output
 1303     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1304     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1305     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1306     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1307     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1308     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1309     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1310     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1311     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1312     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1313     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1314     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1315     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1316     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1317     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1318     # . epilogue
 1319     89/<- %esp 5/r32/ebp
 1320     5d/pop-to-ebp
 1321     c3/return
 1322 
 1323 _pending-test-clobber-dead-local:
 1324     # . prologue
 1325     55/push-ebp
 1326     89/<- %ebp 4/r32/esp
 1327     # setup
 1328     (clear-stream _test-input-stream)
 1329     (clear-stream $_test-input-buffered-file->buffer)
 1330     (clear-stream _test-output-stream)
 1331     (clear-stream $_test-output-buffered-file->buffer)
 1332     #
 1333     (write _test-input-stream "fn foo {\n")
 1334     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1335     (write _test-input-stream "  {\n")
 1336     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1337     (write _test-input-stream "  }\n")
 1338     (write _test-input-stream "}\n")
 1339     # convert
 1340     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1341     (flush _test-output-buffered-file)
 1342 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1348     # check output
 1349     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 1350     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 1351     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 1352     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 1353     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 1354     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 1355     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 1356     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 1357     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 1358     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 1359     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 1360     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 1361     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 1362     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 1363     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 1364     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 1365     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 1366     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 1367     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 1368     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 1369     # . epilogue
 1370     89/<- %esp 5/r32/ebp
 1371     5d/pop-to-ebp
 1372     c3/return
 1373 
 1374 test-shadow-live-local:
 1375     # . prologue
 1376     55/push-ebp
 1377     89/<- %ebp 4/r32/esp
 1378     # setup
 1379     (clear-stream _test-input-stream)
 1380     (clear-stream $_test-input-buffered-file->buffer)
 1381     (clear-stream _test-output-stream)
 1382     (clear-stream $_test-output-buffered-file->buffer)
 1383     #
 1384     (write _test-input-stream "fn foo {\n")
 1385     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1386     (write _test-input-stream "  {\n")
 1387     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1388     (write _test-input-stream "  }\n")
 1389     (write _test-input-stream "  x <- increment\n")
 1390     (write _test-input-stream "}\n")
 1391     # convert
 1392     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1393     (flush _test-output-buffered-file)
 1394 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1400     # check output
 1401     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 1402     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 1403     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 1404     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 1405     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 1406     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 1407     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 1408     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 1409     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 1410     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 1411     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 1412     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 1413     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 1414     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 1415     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 1416     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 1417     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 1418     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 1419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 1420     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 1421     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 1422     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 1423     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/21")
 1424     # . epilogue
 1425     89/<- %esp 5/r32/ebp
 1426     5d/pop-to-ebp
 1427     c3/return
 1428 
 1429 test-do-not-spill-same-register-in-block:
 1430     # . prologue
 1431     55/push-ebp
 1432     89/<- %ebp 4/r32/esp
 1433     # setup
 1434     (clear-stream _test-input-stream)
 1435     (clear-stream $_test-input-buffered-file->buffer)
 1436     (clear-stream _test-output-stream)
 1437     (clear-stream $_test-output-buffered-file->buffer)
 1438     #
 1439     (write _test-input-stream "fn foo {\n")
 1440     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1441     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1442     (write _test-input-stream "  y <- increment\n")
 1443     (write _test-input-stream "}\n")
 1444     # convert
 1445     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1446     (flush _test-output-buffered-file)
 1447 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1453     # check output
 1454     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 1455     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 1456     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 1457     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 1458     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 1459     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 1460     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 1461     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 1462     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 1463     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 1464     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 1465     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 1466     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 1467     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 1468     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 1469     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 1470     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 1471     # . epilogue
 1472     89/<- %esp 5/r32/ebp
 1473     5d/pop-to-ebp
 1474     c3/return
 1475 
 1476 test-spill-different-register-in-block:
 1477     # . prologue
 1478     55/push-ebp
 1479     89/<- %ebp 4/r32/esp
 1480     # setup
 1481     (clear-stream _test-input-stream)
 1482     (clear-stream $_test-input-buffered-file->buffer)
 1483     (clear-stream _test-output-stream)
 1484     (clear-stream $_test-output-buffered-file->buffer)
 1485     #
 1486     (write _test-input-stream "fn foo {\n")
 1487     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 1488     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1489     (write _test-input-stream "  y <- increment\n")
 1490     (write _test-input-stream "}\n")
 1491     # convert
 1492     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1493     (flush _test-output-buffered-file)
 1494 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1500     # check output
 1501     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 1502     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 1503     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 1504     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 1505     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 1506     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 1507     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 1508     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 1509     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 1510     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 1511     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 1512     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 1513     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 1514     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 1515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 1516     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 1517     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 1518     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 1519     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 1520     # . epilogue
 1521     89/<- %esp 5/r32/ebp
 1522     5d/pop-to-ebp
 1523     c3/return
 1524 
 1525 test-shadow-live-output:
 1526     # . prologue
 1527     55/push-ebp
 1528     89/<- %ebp 4/r32/esp
 1529     # setup
 1530     (clear-stream _test-input-stream)
 1531     (clear-stream $_test-input-buffered-file->buffer)
 1532     (clear-stream _test-output-stream)
 1533     (clear-stream $_test-output-buffered-file->buffer)
 1534     #
 1535     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1536     (write _test-input-stream "  x <- copy 3\n")
 1537     (write _test-input-stream "  {\n")
 1538     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1539     (write _test-input-stream "  }\n")
 1540     (write _test-input-stream "  x <- increment\n")
 1541     (write _test-input-stream "}\n")
 1542     # convert
 1543     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1544     (flush _test-output-buffered-file)
 1545 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1551     # check output
 1552     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 1553     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 1554     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 1555     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 1556     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 1557     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 1558     (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
 1559     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 1560     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 1561     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 1562     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 1563     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 1564     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 1565     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 1566     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 1567     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 1568     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 1569     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 1570     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 1571     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 1572     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 1573     # . epilogue
 1574     89/<- %esp 5/r32/ebp
 1575     5d/pop-to-ebp
 1576     c3/return
 1577 
 1578 test-local-clobbered-by-output:
 1579     # also doesn't spill
 1580     # . prologue
 1581     55/push-ebp
 1582     89/<- %ebp 4/r32/esp
 1583     # setup
 1584     (clear-stream _test-input-stream)
 1585     (clear-stream $_test-input-buffered-file->buffer)
 1586     (clear-stream _test-output-stream)
 1587     (clear-stream $_test-output-buffered-file->buffer)
 1588     #
 1589     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1590     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1591     (write _test-input-stream "  x <- copy y\n")
 1592     (write _test-input-stream "}\n")
 1593     # convert
 1594     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1595     (flush _test-output-buffered-file)
 1596 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1602     # check output
 1603     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-output/0")
 1604     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-output/1")
 1605     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-output/2")
 1606     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-output/3")
 1607     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-output/4")
 1608     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-output/5")
 1609     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-output/6")
 1610     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-output/7")
 1611     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-output/8")
 1612     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-output/9")
 1613     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-output/10")
 1614     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-output/11")
 1615     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-output/12")
 1616     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-output/13")
 1617     # . epilogue
 1618     89/<- %esp 5/r32/ebp
 1619     5d/pop-to-ebp
 1620     c3/return
 1621 
 1622 test-read-output:
 1623     # also doesn't spill
 1624     # . prologue
 1625     55/push-ebp
 1626     89/<- %ebp 4/r32/esp
 1627     # setup
 1628     (clear-stream _test-input-stream)
 1629     (clear-stream $_test-input-buffered-file->buffer)
 1630     (clear-stream _test-output-stream)
 1631     (clear-stream $_test-output-buffered-file->buffer)
 1632     #
 1633     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1634     (write _test-input-stream "  x <- copy 0x34\n")
 1635     (write _test-input-stream "  compare x, 0x35\n")
 1636     (write _test-input-stream "}\n")
 1637     # convert
 1638     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1639     (flush _test-output-buffered-file)
 1640 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1646     # check output
 1647     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 1648     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 1649     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 1650     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 1651     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 1652     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 1653     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 1654     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 1655     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 1656     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 1657     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 1658     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 1659     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 1660     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 1661     # . epilogue
 1662     89/<- %esp 5/r32/ebp
 1663     5d/pop-to-ebp
 1664     c3/return
 1665 
 1666 test-convert-function-with-branches-in-block:
 1667     # . prologue
 1668     55/push-ebp
 1669     89/<- %ebp 4/r32/esp
 1670     # setup
 1671     (clear-stream _test-input-stream)
 1672     (clear-stream $_test-input-buffered-file->buffer)
 1673     (clear-stream _test-output-stream)
 1674     (clear-stream $_test-output-buffered-file->buffer)
 1675     #
 1676     (write _test-input-stream "fn foo x: int {\n")
 1677     (write _test-input-stream "  {\n")
 1678     (write _test-input-stream "    break-if->=\n")
 1679     (write _test-input-stream "    loop-if-addr<\n")
 1680     (write _test-input-stream "    increment x\n")
 1681     (write _test-input-stream "    loop\n")
 1682     (write _test-input-stream "  }\n")
 1683     (write _test-input-stream "}\n")
 1684     # convert
 1685     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1686     (flush _test-output-buffered-file)
 1687 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1693     # check output
 1694     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 1695     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 1696     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 1697     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 1698     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 1699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 1700     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 1701     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 1702     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 1703     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 1704     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 1705     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 1706     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 1707     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 1708     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 1709     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 1710     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 1711     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 1712     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 1713     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 1714     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 1715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 1716     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 1717     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 1718     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 1719     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 1720     # . epilogue
 1721     89/<- %esp 5/r32/ebp
 1722     5d/pop-to-ebp
 1723     c3/return
 1724 
 1725 test-convert-function-with-branches-in-named-block:
 1726     # . prologue
 1727     55/push-ebp
 1728     89/<- %ebp 4/r32/esp
 1729     # setup
 1730     (clear-stream _test-input-stream)
 1731     (clear-stream $_test-input-buffered-file->buffer)
 1732     (clear-stream _test-output-stream)
 1733     (clear-stream $_test-output-buffered-file->buffer)
 1734     #
 1735     (write _test-input-stream "fn foo x: int {\n")
 1736     (write _test-input-stream "  $bar: {\n")
 1737     (write _test-input-stream "    break-if->= $bar\n")
 1738     (write _test-input-stream "    loop-if-addr< $bar\n")
 1739     (write _test-input-stream "    increment x\n")
 1740     (write _test-input-stream "    loop\n")
 1741     (write _test-input-stream "  }\n")
 1742     (write _test-input-stream "}\n")
 1743     # convert
 1744     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1745     (flush _test-output-buffered-file)
 1746 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1752     # check output
 1753     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 1754     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 1755     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 1756     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 1757     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 1758     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 1759     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 1760     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 1761     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 1762     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 1763     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 1764     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 1765     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 1766     (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")
 1767     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 1768     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 1769     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 1770     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 1771     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 1772     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 1773     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 1774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 1775     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 1776     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 1777     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 1778     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 1779     # . epilogue
 1780     89/<- %esp 5/r32/ebp
 1781     5d/pop-to-ebp
 1782     c3/return
 1783 
 1784 test-convert-function-with-var-in-nested-block:
 1785     # . prologue
 1786     55/push-ebp
 1787     89/<- %ebp 4/r32/esp
 1788     # setup
 1789     (clear-stream _test-input-stream)
 1790     (clear-stream $_test-input-buffered-file->buffer)
 1791     (clear-stream _test-output-stream)
 1792     (clear-stream $_test-output-buffered-file->buffer)
 1793     #
 1794     (write _test-input-stream "fn foo x: int {\n")
 1795     (write _test-input-stream "  {\n")
 1796     (write _test-input-stream "    {\n")
 1797     (write _test-input-stream "      var x: int\n")
 1798     (write _test-input-stream "      increment x\n")
 1799     (write _test-input-stream "    }\n")
 1800     (write _test-input-stream "  }\n")
 1801     (write _test-input-stream "}\n")
 1802     # convert
 1803     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1804     (flush _test-output-buffered-file)
 1805 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1811     # check output
 1812     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 1813     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 1814     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 1815     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 1816     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 1817     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 1818     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 1819     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 1820     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 1821     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 1822     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 1823     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 1824     (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")
 1825     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 1826     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 1827     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 1828     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 1829     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 1830     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 1831     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 1832     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 1833     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 1834     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 1835     # . epilogue
 1836     89/<- %esp 5/r32/ebp
 1837     5d/pop-to-ebp
 1838     c3/return
 1839 
 1840 test-convert-function-with-multiple-vars-in-nested-blocks:
 1841     # . prologue
 1842     55/push-ebp
 1843     89/<- %ebp 4/r32/esp
 1844     # setup
 1845     (clear-stream _test-input-stream)
 1846     (clear-stream $_test-input-buffered-file->buffer)
 1847     (clear-stream _test-output-stream)
 1848     (clear-stream $_test-output-buffered-file->buffer)
 1849     #
 1850     (write _test-input-stream "fn foo x: int {\n")
 1851     (write _test-input-stream "  {\n")
 1852     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 1853     (write _test-input-stream "    {\n")
 1854     (write _test-input-stream "      var y: int\n")
 1855     (write _test-input-stream "      x <- add y\n")
 1856     (write _test-input-stream "    }\n")
 1857     (write _test-input-stream "  }\n")
 1858     (write _test-input-stream "}\n")
 1859     # convert
 1860     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1861     (flush _test-output-buffered-file)
 1862 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1868     # check output
 1869     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 1870     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 1871     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 1872     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 1873     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 1874     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 1875     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 1876     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 1877     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 1878     (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")
 1879     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 1880     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 1881     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 1882     (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")
 1883     (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")
 1884     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 1885     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 1886     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 1887     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 1888     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 1889     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 1890     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 1891     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 1892     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 1893     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 1894     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 1895     # . epilogue
 1896     89/<- %esp 5/r32/ebp
 1897     5d/pop-to-ebp
 1898     c3/return
 1899 
 1900 test-convert-function-with-branches-and-local-vars:
 1901     # A conditional 'break' after a 'var' in a block is converted into a
 1902     # nested block that performs all necessary cleanup before jumping. This
 1903     # results in some ugly code duplication.
 1904     # . prologue
 1905     55/push-ebp
 1906     89/<- %ebp 4/r32/esp
 1907     # setup
 1908     (clear-stream _test-input-stream)
 1909     (clear-stream $_test-input-buffered-file->buffer)
 1910     (clear-stream _test-output-stream)
 1911     (clear-stream $_test-output-buffered-file->buffer)
 1912     #
 1913     (write _test-input-stream "fn foo {\n")
 1914     (write _test-input-stream "  {\n")
 1915     (write _test-input-stream "    var x: int\n")
 1916     (write _test-input-stream "    break-if->=\n")
 1917     (write _test-input-stream "    increment x\n")
 1918     (write _test-input-stream "  }\n")
 1919     (write _test-input-stream "}\n")
 1920     # convert
 1921     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1922     (flush _test-output-buffered-file)
 1923 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1929     # check output
 1930     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 1931     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 1932     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 1933     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 1934     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 1935     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 1936     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 1937     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 1938     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 1939     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 1940     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 1941     (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")
 1942     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 1943     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 1944     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 1945     (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")
 1946     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 1947     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 1948     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 1949     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 1950     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 1951     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 1952     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 1953     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 1954     # . epilogue
 1955     89/<- %esp 5/r32/ebp
 1956     5d/pop-to-ebp
 1957     c3/return
 1958 
 1959 test-convert-function-with-conditional-loops-and-local-vars:
 1960     # A conditional 'loop' after a 'var' in a block is converted into a nested
 1961     # block that performs all necessary cleanup before jumping. This results
 1962     # in some ugly code duplication.
 1963     # . prologue
 1964     55/push-ebp
 1965     89/<- %ebp 4/r32/esp
 1966     # setup
 1967     (clear-stream _test-input-stream)
 1968     (clear-stream $_test-input-buffered-file->buffer)
 1969     (clear-stream _test-output-stream)
 1970     (clear-stream $_test-output-buffered-file->buffer)
 1971     #
 1972     (write _test-input-stream "fn foo {\n")
 1973     (write _test-input-stream "  {\n")
 1974     (write _test-input-stream "    var x: int\n")
 1975     (write _test-input-stream "    loop-if->=\n")
 1976     (write _test-input-stream "    increment x\n")
 1977     (write _test-input-stream "  }\n")
 1978     (write _test-input-stream "}\n")
 1979     # convert
 1980     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 1981     (flush _test-output-buffered-file)
 1982 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 1988     # check output
 1989     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 1990     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 1991     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 1992     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 1993     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 1994     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 1995     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 1996     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 1997     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 1998     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 1999     (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")
 2000     (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")
 2001     (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")
 2002     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2003     (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")
 2004     (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")
 2005     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2006     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2007     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2008     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2009     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2010     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2011     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2012     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2013     # . epilogue
 2014     89/<- %esp 5/r32/ebp
 2015     5d/pop-to-ebp
 2016     c3/return
 2017 
 2018 test-convert-function-with-unconditional-loops-and-local-vars:
 2019     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2020     # regular block cleanup. Any instructions after 'loop' are dead and
 2021     # therefore skipped.
 2022     # . prologue
 2023     55/push-ebp
 2024     89/<- %ebp 4/r32/esp
 2025     # setup
 2026     (clear-stream _test-input-stream)
 2027     (clear-stream $_test-input-buffered-file->buffer)
 2028     (clear-stream _test-output-stream)
 2029     (clear-stream $_test-output-buffered-file->buffer)
 2030     #
 2031     (write _test-input-stream "fn foo {\n")
 2032     (write _test-input-stream "  {\n")
 2033     (write _test-input-stream "    var x: int\n")
 2034     (write _test-input-stream "    loop\n")
 2035     (write _test-input-stream "    increment x\n")
 2036     (write _test-input-stream "  }\n")
 2037     (write _test-input-stream "}\n")
 2038     # convert
 2039     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2040     (flush _test-output-buffered-file)
 2041 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2047     # check output
 2048     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2049     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2050     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2051     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2052     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2053     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2054     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2055     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2056     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2057     (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")
 2058     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2059     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2060     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2061     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2062     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2063     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2064     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2065     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2066     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2067     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2068     # . epilogue
 2069     89/<- %esp 5/r32/ebp
 2070     5d/pop-to-ebp
 2071     c3/return
 2072 
 2073 test-convert-function-with-branches-and-loops-and-local-vars:
 2074     # . prologue
 2075     55/push-ebp
 2076     89/<- %ebp 4/r32/esp
 2077     # setup
 2078     (clear-stream _test-input-stream)
 2079     (clear-stream $_test-input-buffered-file->buffer)
 2080     (clear-stream _test-output-stream)
 2081     (clear-stream $_test-output-buffered-file->buffer)
 2082     #
 2083     (write _test-input-stream "fn foo {\n")
 2084     (write _test-input-stream "  {\n")
 2085     (write _test-input-stream "    var x: int\n")
 2086     (write _test-input-stream "    break-if->=\n")
 2087     (write _test-input-stream "    increment x\n")
 2088     (write _test-input-stream "    loop\n")
 2089     (write _test-input-stream "  }\n")
 2090     (write _test-input-stream "}\n")
 2091     # convert
 2092     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2093     (flush _test-output-buffered-file)
 2094 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2100     # check output
 2101     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2102     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2103     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2104     (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")
 2105     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2106     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2107     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2108     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2109     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2110     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2111     (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")
 2112     (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")
 2113     (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")
 2114     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2115     (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")
 2116     (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")
 2117     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2118     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2119     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2123     (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")
 2124     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2126     # . epilogue
 2127     89/<- %esp 5/r32/ebp
 2128     5d/pop-to-ebp
 2129     c3/return
 2130 
 2131 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 2132     # . prologue
 2133     55/push-ebp
 2134     89/<- %ebp 4/r32/esp
 2135     # setup
 2136     (clear-stream _test-input-stream)
 2137     (clear-stream $_test-input-buffered-file->buffer)
 2138     (clear-stream _test-output-stream)
 2139     (clear-stream $_test-output-buffered-file->buffer)
 2140     #
 2141     (write _test-input-stream "fn foo {\n")
 2142     (write _test-input-stream "  a: {\n")
 2143     (write _test-input-stream "    var x: int\n")
 2144     (write _test-input-stream "    {\n")
 2145     (write _test-input-stream "      var y: int\n")
 2146     (write _test-input-stream "      break-if->= a\n")
 2147     (write _test-input-stream "      increment x\n")
 2148     (write _test-input-stream "      loop\n")
 2149     (write _test-input-stream "    }\n")
 2150     (write _test-input-stream "  }\n")
 2151     (write _test-input-stream "}\n")
 2152     # convert
 2153     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2154     (flush _test-output-buffered-file)
 2155 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2161     # check output
 2162     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 2163     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 2164     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 2165     (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")
 2166     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 2167     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 2168     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 2169     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 2170     (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")
 2171     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 2172     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 2173     (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")
 2174     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 2175     (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")
 2176     (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")
 2177     (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")
 2178     (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")
 2179     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 2180     (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")
 2181     (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")
 2182     (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")
 2183     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 2184     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 2185     (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")
 2186     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 2187     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 2188     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 2189     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 2190     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 2191     (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")
 2192     (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")
 2193     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 2194     # . epilogue
 2195     89/<- %esp 5/r32/ebp
 2196     5d/pop-to-ebp
 2197     c3/return
 2198 
 2199 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 2200     # . prologue
 2201     55/push-ebp
 2202     89/<- %ebp 4/r32/esp
 2203     # setup
 2204     (clear-stream _test-input-stream)
 2205     (clear-stream $_test-input-buffered-file->buffer)
 2206     (clear-stream _test-output-stream)
 2207     (clear-stream $_test-output-buffered-file->buffer)
 2208     # non-local conditional branch from a block without a local variable,
 2209     # unwinding a local on the stack
 2210     (write _test-input-stream "fn foo {\n")
 2211     (write _test-input-stream "  a: {\n")
 2212     (write _test-input-stream "    var x: int\n")
 2213     (write _test-input-stream "    {\n")
 2214     (write _test-input-stream "      break-if->= a\n")
 2215     (write _test-input-stream "    }\n")
 2216     (write _test-input-stream "  }\n")
 2217     (write _test-input-stream "}\n")
 2218     # convert
 2219     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2220     (flush _test-output-buffered-file)
 2221 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2227     # check output
 2228     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 2229     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 2230     (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")
 2231     (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")
 2232     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 2233     (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")
 2234     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 2235     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 2236     (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")
 2237     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 2238     (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")
 2239     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 2240     (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")
 2241     (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")
 2242     (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")
 2243     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 2244     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 2245     (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")
 2246     (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")
 2247     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 2248     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 2249     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 2250     (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")
 2251     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 2252     (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")
 2253     (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")
 2254     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 2255     # . epilogue
 2256     89/<- %esp 5/r32/ebp
 2257     5d/pop-to-ebp
 2258     c3/return
 2259 
 2260 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 2261     # . prologue
 2262     55/push-ebp
 2263     89/<- %ebp 4/r32/esp
 2264     # setup
 2265     (clear-stream _test-input-stream)
 2266     (clear-stream $_test-input-buffered-file->buffer)
 2267     (clear-stream _test-output-stream)
 2268     (clear-stream $_test-output-buffered-file->buffer)
 2269     # non-local unconditional branch from a block without a local variable,
 2270     # unwinding a local on the stack
 2271     (write _test-input-stream "fn foo {\n")
 2272     (write _test-input-stream "  a: {\n")
 2273     (write _test-input-stream "    var x: int\n")
 2274     (write _test-input-stream "    {\n")
 2275     (write _test-input-stream "      break a\n")
 2276     (write _test-input-stream "    }\n")
 2277     (write _test-input-stream "  }\n")
 2278     (write _test-input-stream "}\n")
 2279     # convert
 2280     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2281     (flush _test-output-buffered-file)
 2282 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2288     # check output
 2289     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 2290     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 2291     (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")
 2292     (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")
 2293     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 2294     (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")
 2295     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 2296     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 2297     (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")
 2298     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 2299     (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")
 2300     (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")
 2301     (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")
 2302     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 2303     (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")
 2304     (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")
 2305     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 2306     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 2307     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 2308     (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")
 2309     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 2310     (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")
 2311     (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")
 2312     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 2313     # . epilogue
 2314     89/<- %esp 5/r32/ebp
 2315     5d/pop-to-ebp
 2316     c3/return
 2317 
 2318 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 2319     # . prologue
 2320     55/push-ebp
 2321     89/<- %ebp 4/r32/esp
 2322     # setup
 2323     (clear-stream _test-input-stream)
 2324     (clear-stream $_test-input-buffered-file->buffer)
 2325     (clear-stream _test-output-stream)
 2326     (clear-stream $_test-output-buffered-file->buffer)
 2327     #
 2328     (write _test-input-stream "fn foo {\n")
 2329     (write _test-input-stream "  a: {\n")
 2330     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 2331     (write _test-input-stream "    {\n")
 2332     (write _test-input-stream "      break a\n")
 2333     (write _test-input-stream "    }\n")
 2334     (write _test-input-stream "  }\n")
 2335     (write _test-input-stream "}\n")
 2336     # convert
 2337     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2338     (flush _test-output-buffered-file)
 2339 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2345     # check output
 2346     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 2347     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 2348     (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")
 2349     (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")
 2350     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 2351     (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")
 2352     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 2353     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 2354     (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")
 2355     (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")
 2356     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 2357     (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")
 2358     (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")
 2359     (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")
 2360     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 2361     (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")
 2362     (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")
 2363     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 2364     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 2365     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 2366     (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")
 2367     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 2368     (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")
 2369     (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")
 2370     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 2371     # . epilogue
 2372     89/<- %esp 5/r32/ebp
 2373     5d/pop-to-ebp
 2374     c3/return
 2375 
 2376 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 2377     # . prologue
 2378     55/push-ebp
 2379     89/<- %ebp 4/r32/esp
 2380     # setup
 2381     (clear-stream _test-input-stream)
 2382     (clear-stream $_test-input-buffered-file->buffer)
 2383     (clear-stream _test-output-stream)
 2384     (clear-stream $_test-output-buffered-file->buffer)
 2385     #
 2386     (write _test-input-stream "fn foo {\n")
 2387     (write _test-input-stream "  a: {\n")
 2388     (write _test-input-stream "    var x: int\n")
 2389     (write _test-input-stream "    {\n")
 2390     (write _test-input-stream "      var y: int\n")
 2391     (write _test-input-stream "      break a\n")
 2392     (write _test-input-stream "      increment x\n")
 2393     (write _test-input-stream "    }\n")
 2394     (write _test-input-stream "  }\n")
 2395     (write _test-input-stream "}\n")
 2396     # convert
 2397     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2398     (flush _test-output-buffered-file)
 2399 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2405     # check output
 2406     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 2407     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 2408     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 2409     (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")
 2410     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 2411     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 2412     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 2413     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 2414     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 2415     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 2416     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 2417     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 2418     (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")
 2419     (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")
 2420     (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")
 2421     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 2422     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 2423     (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")
 2424     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 2425     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 2426     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 2427     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 2428     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 2429     (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")
 2430     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 2431     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 2432     # . epilogue
 2433     89/<- %esp 5/r32/ebp
 2434     5d/pop-to-ebp
 2435     c3/return
 2436 
 2437 test-convert-function-with-unconditional-break-and-local-vars:
 2438     # . prologue
 2439     55/push-ebp
 2440     89/<- %ebp 4/r32/esp
 2441     # setup
 2442     (clear-stream _test-input-stream)
 2443     (clear-stream $_test-input-buffered-file->buffer)
 2444     (clear-stream _test-output-stream)
 2445     (clear-stream $_test-output-buffered-file->buffer)
 2446     #
 2447     (write _test-input-stream "fn foo {\n")
 2448     (write _test-input-stream "  {\n")
 2449     (write _test-input-stream "    var x: int\n")
 2450     (write _test-input-stream "    {\n")
 2451     (write _test-input-stream "      var y: int\n")
 2452     (write _test-input-stream "      break\n")
 2453     (write _test-input-stream "      increment x\n")
 2454     (write _test-input-stream "    }\n")
 2455     (write _test-input-stream "  }\n")
 2456     (write _test-input-stream "}\n")
 2457     # convert
 2458     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2459     (flush _test-output-buffered-file)
 2460 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2466     # check output
 2467     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 2468     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 2469     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 2470     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 2471     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 2472     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 2473     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 2474     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 2475     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 2476     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 2477     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 2478     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 2479     (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")
 2480     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 2481     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 2482     (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")
 2483     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 2484     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 2485     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 2486     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 2487     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 2488     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 2489     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 2490     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 2491     # . epilogue
 2492     89/<- %esp 5/r32/ebp
 2493     5d/pop-to-ebp
 2494     c3/return
 2495 
 2496 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 2497     # . prologue
 2498     55/push-ebp
 2499     89/<- %ebp 4/r32/esp
 2500     # setup
 2501     (clear-stream _test-input-stream)
 2502     (clear-stream $_test-input-buffered-file->buffer)
 2503     (clear-stream _test-output-stream)
 2504     (clear-stream $_test-output-buffered-file->buffer)
 2505     #
 2506     (write _test-input-stream "fn foo {\n")
 2507     (write _test-input-stream "  a: {\n")
 2508     (write _test-input-stream "    var x: int\n")
 2509     (write _test-input-stream "    {\n")
 2510     (write _test-input-stream "      var y: int\n")
 2511     (write _test-input-stream "      loop a\n")
 2512     (write _test-input-stream "      increment x\n")
 2513     (write _test-input-stream "    }\n")
 2514     (write _test-input-stream "  }\n")
 2515     (write _test-input-stream "}\n")
 2516     # convert
 2517     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2518     (flush _test-output-buffered-file)
 2519 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2525     # check output
 2526     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 2527     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 2528     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 2529     (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")
 2530     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 2531     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 2532     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 2533     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 2534     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 2535     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 2536     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 2537     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 2538     (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")
 2539     (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")
 2540     (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")
 2541     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 2542     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 2543     (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")
 2544     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 2545     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 2546     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 2547     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 2548     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 2549     (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")
 2550     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 2551     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 2552     # . epilogue
 2553     89/<- %esp 5/r32/ebp
 2554     5d/pop-to-ebp
 2555     c3/return
 2556 
 2557 test-convert-function-with-local-array-var-in-mem:
 2558     # . prologue
 2559     55/push-ebp
 2560     89/<- %ebp 4/r32/esp
 2561     # setup
 2562     (clear-stream _test-input-stream)
 2563     (clear-stream $_test-input-buffered-file->buffer)
 2564     (clear-stream _test-output-stream)
 2565     (clear-stream $_test-output-buffered-file->buffer)
 2566     #
 2567     (write _test-input-stream "fn foo {\n")
 2568     (write _test-input-stream "  var x: (array int 3)\n")
 2569     (write _test-input-stream "}\n")
 2570     # convert
 2571     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2572     (flush _test-output-buffered-file)
 2573 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2579     # check output
 2580     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 2581     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 2582     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 2583     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 2584     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 2585     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 2586     # define x
 2587     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 2588     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 2589     # reclaim x
 2590     (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")
 2591     #
 2592     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 2593     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 2594     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 2595     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 2596     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 2597     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 2598     # . epilogue
 2599     89/<- %esp 5/r32/ebp
 2600     5d/pop-to-ebp
 2601     c3/return
 2602 
 2603 test-convert-address:
 2604     # . prologue
 2605     55/push-ebp
 2606     89/<- %ebp 4/r32/esp
 2607     # setup
 2608     (clear-stream _test-input-stream)
 2609     (clear-stream $_test-input-buffered-file->buffer)
 2610     (clear-stream _test-output-stream)
 2611     (clear-stream $_test-output-buffered-file->buffer)
 2612     #
 2613     (write _test-input-stream "fn foo {\n")
 2614     (write _test-input-stream "  var a: int\n")
 2615     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 2616     (write _test-input-stream "}\n")
 2617     # convert
 2618     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2619     (flush _test-output-buffered-file)
 2620 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2626     # check output
 2627     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 2628     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 2629     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 2630     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 2631     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 2632     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 2633     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 2634     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 2635     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 2636     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 2637     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 2638     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 2639     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 2640     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 2641     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 2642     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 2643     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 2644     # . epilogue
 2645     89/<- %esp 5/r32/ebp
 2646     5d/pop-to-ebp
 2647     c3/return
 2648 
 2649 test-convert-length-of-array:
 2650     # . prologue
 2651     55/push-ebp
 2652     89/<- %ebp 4/r32/esp
 2653     # setup
 2654     (clear-stream _test-input-stream)
 2655     (clear-stream $_test-input-buffered-file->buffer)
 2656     (clear-stream _test-output-stream)
 2657     (clear-stream $_test-output-buffered-file->buffer)
 2658     #
 2659     (write _test-input-stream "fn foo a: (addr array int) {\n")
 2660     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 2661     (write _test-input-stream "  var c/eax: int <- length b\n")
 2662     (write _test-input-stream "}\n")
 2663     # convert
 2664     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2665     (flush _test-output-buffered-file)
 2666 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2672     # check output
 2673     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 2674     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 2675     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 2676     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 2677     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 2678     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 2679     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 2680     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 2681     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 2682     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 2683     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 2684     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 2685     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 2686     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 2687     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 2688     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 2689     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 2690     # . epilogue
 2691     89/<- %esp 5/r32/ebp
 2692     5d/pop-to-ebp
 2693     c3/return
 2694 
 2695 test-convert-length-of-array-on-stack:
 2696     # . prologue
 2697     55/push-ebp
 2698     89/<- %ebp 4/r32/esp
 2699     # setup
 2700     (clear-stream _test-input-stream)
 2701     (clear-stream $_test-input-buffered-file->buffer)
 2702     (clear-stream _test-output-stream)
 2703     (clear-stream $_test-output-buffered-file->buffer)
 2704     #
 2705     (write _test-input-stream "fn foo {\n")
 2706     (write _test-input-stream "  var a: (array int 3)\n")
 2707     (write _test-input-stream "  var b/eax: int <- length a\n")
 2708     (write _test-input-stream "}\n")
 2709     # convert
 2710     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2711     (flush _test-output-buffered-file)
 2712 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2718     # check output
 2719     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 2720     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 2721     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 2722     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 2723     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 2724     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 2725     # define x
 2726     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 2727     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 2728     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 2729     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 2730     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 2731     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 2732     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 2733     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 2734     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 2735     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 2736     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 2737     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 2738     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 2739     # . epilogue
 2740     89/<- %esp 5/r32/ebp
 2741     5d/pop-to-ebp
 2742     c3/return
 2743 
 2744 test-convert-index-into-array:
 2745     # . prologue
 2746     55/push-ebp
 2747     89/<- %ebp 4/r32/esp
 2748     # setup
 2749     (clear-stream _test-input-stream)
 2750     (clear-stream $_test-input-buffered-file->buffer)
 2751     (clear-stream _test-output-stream)
 2752     (clear-stream $_test-output-buffered-file->buffer)
 2753     #
 2754     (write _test-input-stream "fn foo {\n")
 2755     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2756     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 2757     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2758     (write _test-input-stream "}\n")
 2759     # convert
 2760     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2761     (flush _test-output-buffered-file)
 2762 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2768     # check output
 2769     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 2770     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 2771     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 2772     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 2773     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 2774     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 2775     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 2776     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 2777     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 2778     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 2779     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/11")
 2780     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/13")
 2781     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/14")
 2782     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/15")
 2783     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/16")
 2784     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/17")
 2785     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/18")
 2786     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/19")
 2787     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/20")
 2788     # . epilogue
 2789     89/<- %esp 5/r32/ebp
 2790     5d/pop-to-ebp
 2791     c3/return
 2792 
 2793 test-convert-index-into-array-with-literal:
 2794     # . prologue
 2795     55/push-ebp
 2796     89/<- %ebp 4/r32/esp
 2797     # setup
 2798     (clear-stream _test-input-stream)
 2799     (clear-stream $_test-input-buffered-file->buffer)
 2800     (clear-stream _test-output-stream)
 2801     (clear-stream $_test-output-buffered-file->buffer)
 2802     #
 2803     (write _test-input-stream "fn foo {\n")
 2804     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2805     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 2806     (write _test-input-stream "}\n")
 2807     # convert
 2808     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2809     (flush _test-output-buffered-file)
 2810 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2816     # check output
 2817     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 2818     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 2819     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 2820     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 2821     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 2822     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 2823     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 2824     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 2825                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 2826     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 2827     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 2828     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 2829     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 2830     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 2831     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 2832     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 2833     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 2834     # . epilogue
 2835     89/<- %esp 5/r32/ebp
 2836     5d/pop-to-ebp
 2837     c3/return
 2838 
 2839 test-convert-index-into-array-on-stack:
 2840     # . prologue
 2841     55/push-ebp
 2842     89/<- %ebp 4/r32/esp
 2843     # setup
 2844     (clear-stream _test-input-stream)
 2845     (clear-stream $_test-input-buffered-file->buffer)
 2846     (clear-stream _test-output-stream)
 2847     (clear-stream $_test-output-buffered-file->buffer)
 2848     #
 2849     (write _test-input-stream "fn foo {\n")
 2850     (write _test-input-stream "  var arr: (array int 3)\n")
 2851     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 2852     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2853     (write _test-input-stream "}\n")
 2854     # convert
 2855     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2856     (flush _test-output-buffered-file)
 2857 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2863     # check output
 2864     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 2865     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 2866     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 2867     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 2868     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 2869     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 2870     # var arr
 2871     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 2872     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 2873     # var idx
 2874     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 2875     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 2876     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 2877     (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")
 2878     # reclaim idx
 2879     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 2880     # reclaim arr
 2881     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 2882     #
 2883     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 2884     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 2885     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 2886     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 2887     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 2888     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 2889     # . epilogue
 2890     89/<- %esp 5/r32/ebp
 2891     5d/pop-to-ebp
 2892     c3/return
 2893 
 2894 test-convert-index-into-array-on-stack-with-literal:
 2895     # . prologue
 2896     55/push-ebp
 2897     89/<- %ebp 4/r32/esp
 2898     # setup
 2899     (clear-stream _test-input-stream)
 2900     (clear-stream $_test-input-buffered-file->buffer)
 2901     (clear-stream _test-output-stream)
 2902     (clear-stream $_test-output-buffered-file->buffer)
 2903     #
 2904     (write _test-input-stream "fn foo {\n")
 2905     (write _test-input-stream "  var arr: (array int 3)\n")
 2906     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 2907     (write _test-input-stream "}\n")
 2908     # convert
 2909     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2910     (flush _test-output-buffered-file)
 2911 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2917     # check output
 2918     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 2919     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 2920     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 2921     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 2922     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 2923     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 2924     # var arr
 2925     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 2926     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 2927     # var x
 2928     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 2929     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 2930     (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")
 2931     # reclaim x
 2932     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 2933     # reclaim arr
 2934     (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")
 2935     #
 2936     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 2937     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 2938     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 2939     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 2940     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 2941     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 2942     # . epilogue
 2943     89/<- %esp 5/r32/ebp
 2944     5d/pop-to-ebp
 2945     c3/return
 2946 
 2947 test-convert-index-into-array-using-offset:
 2948     # . prologue
 2949     55/push-ebp
 2950     89/<- %ebp 4/r32/esp
 2951     # setup
 2952     (clear-stream _test-input-stream)
 2953     (clear-stream $_test-input-buffered-file->buffer)
 2954     (clear-stream _test-output-stream)
 2955     (clear-stream $_test-output-buffered-file->buffer)
 2956     #
 2957     (write _test-input-stream "fn foo {\n")
 2958     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2959     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 2960     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 2961     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 2962     (write _test-input-stream "}\n")
 2963     # convert
 2964     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 2965     (flush _test-output-buffered-file)
 2966 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 2972     # check output
 2973     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 2974     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 2975     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 2976     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 2977     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 2978     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 2979     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 2980     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 2981     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 2982     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 2983     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 2984     (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")
 2985     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 2986     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 2987     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 2988     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 2989     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 2990     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 2991     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 2992     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 2993     # . epilogue
 2994     89/<- %esp 5/r32/ebp
 2995     5d/pop-to-ebp
 2996     c3/return
 2997 
 2998 test-convert-index-into-array-using-offset-on-stack:
 2999     # . prologue
 3000     55/push-ebp
 3001     89/<- %ebp 4/r32/esp
 3002     # setup
 3003     (clear-stream _test-input-stream)
 3004     (clear-stream $_test-input-buffered-file->buffer)
 3005     (clear-stream _test-output-stream)
 3006     (clear-stream $_test-output-buffered-file->buffer)
 3007     #
 3008     (write _test-input-stream "fn foo {\n")
 3009     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3010     (write _test-input-stream "  var idx: int\n")
 3011     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 3012     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 3013     (write _test-input-stream "}\n")
 3014     # convert
 3015     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3016     (flush _test-output-buffered-file)
 3017 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3023     # check output
 3024     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 3025     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 3026     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 3027     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 3028     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 3029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 3030     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 3031     (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")
 3032     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 3033     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 3034     (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")
 3035     (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")
 3036     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 3037     (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")
 3038     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 3039     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 3040     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 3041     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 3042     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 3043     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 3044     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 3045     # . epilogue
 3046     89/<- %esp 5/r32/ebp
 3047     5d/pop-to-ebp
 3048     c3/return
 3049 
 3050 test-convert-function-and-type-definition:
 3051     # . prologue
 3052     55/push-ebp
 3053     89/<- %ebp 4/r32/esp
 3054     # setup
 3055     (clear-stream _test-input-stream)
 3056     (clear-stream $_test-input-buffered-file->buffer)
 3057     (clear-stream _test-output-stream)
 3058     (clear-stream $_test-output-buffered-file->buffer)
 3059     #
 3060     (write _test-input-stream "fn foo a: (addr t) {\n")
 3061     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 3062     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 3063     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 3064     (write _test-input-stream "}\n")
 3065     (write _test-input-stream "type t {\n")
 3066     (write _test-input-stream "  x: int\n")
 3067     (write _test-input-stream "  y: int\n")
 3068     (write _test-input-stream "}\n")
 3069     # convert
 3070     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3071     (flush _test-output-buffered-file)
 3072 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3078     # check output
 3079     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 3080     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 3081     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 3082     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 3083     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 3084     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 3085     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 3086     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 3087     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 3088     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 3089     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 3090     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 3091     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 3092     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 3093     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 3094     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 3095     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 3096     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 3097     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 3098     # . epilogue
 3099     89/<- %esp 5/r32/ebp
 3100     5d/pop-to-ebp
 3101     c3/return
 3102 
 3103 test-convert-function-with-local-var-with-user-defined-type:
 3104     # . prologue
 3105     55/push-ebp
 3106     89/<- %ebp 4/r32/esp
 3107     # setup
 3108     (clear-stream _test-input-stream)
 3109     (clear-stream $_test-input-buffered-file->buffer)
 3110     (clear-stream _test-output-stream)
 3111     (clear-stream $_test-output-buffered-file->buffer)
 3112     #
 3113     (write _test-input-stream "fn foo {\n")
 3114     (write _test-input-stream "  var a: t\n")
 3115     (write _test-input-stream "}\n")
 3116     (write _test-input-stream "type t {\n")
 3117     (write _test-input-stream "  x: int\n")
 3118     (write _test-input-stream "  y: int\n")
 3119     (write _test-input-stream "}\n")
 3120     # convert
 3121     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3122     (flush _test-output-buffered-file)
 3123 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3129     # check output
 3130     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 3131     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 3132     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 3133     (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")
 3134     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 3135     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 3136     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 3137     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 3138     (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")
 3139     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 3140     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 3141     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 3142     (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")
 3143     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 3144     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 3145     # . epilogue
 3146     89/<- %esp 5/r32/ebp
 3147     5d/pop-to-ebp
 3148     c3/return
 3149 
 3150 test-convert-function-call-with-arg-of-user-defined-type:
 3151     # . prologue
 3152     55/push-ebp
 3153     89/<- %ebp 4/r32/esp
 3154     # setup
 3155     (clear-stream _test-input-stream)
 3156     (clear-stream $_test-input-buffered-file->buffer)
 3157     (clear-stream _test-output-stream)
 3158     (clear-stream $_test-output-buffered-file->buffer)
 3159     #
 3160     (write _test-input-stream "fn f {\n")
 3161     (write _test-input-stream "  var a: t\n")
 3162     (write _test-input-stream "  foo a\n")
 3163     (write _test-input-stream "}\n")
 3164     (write _test-input-stream "fn foo x: t {\n")
 3165     (write _test-input-stream "}\n")
 3166     (write _test-input-stream "type t {\n")
 3167     (write _test-input-stream "  x: int\n")
 3168     (write _test-input-stream "  y: int\n")
 3169     (write _test-input-stream "}\n")
 3170     # convert
 3171     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3172     (flush _test-output-buffered-file)
 3173 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3179     # check output
 3180     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 3181     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 3182     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 3183     (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")
 3184     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 3185     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 3186     # var a: t
 3187     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 3188     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 3189     # foo a
 3190     (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")
 3191     #
 3192     (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")
 3193     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 3194     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 3195     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 3196     (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")
 3197     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 3198     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 3199     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 3200     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 3201     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 3202     (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")
 3203     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 3204     (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")
 3205     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 3206     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 3207     # . epilogue
 3208     89/<- %esp 5/r32/ebp
 3209     5d/pop-to-ebp
 3210     c3/return
 3211 
 3212 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 3213     # . prologue
 3214     55/push-ebp
 3215     89/<- %ebp 4/r32/esp
 3216     # setup
 3217     (clear-stream _test-input-stream)
 3218     (clear-stream $_test-input-buffered-file->buffer)
 3219     (clear-stream _test-output-stream)
 3220     (clear-stream $_test-output-buffered-file->buffer)
 3221     #
 3222     (write _test-input-stream "fn f {\n")
 3223     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 3224     (write _test-input-stream "  foo *a\n")
 3225     (write _test-input-stream "}\n")
 3226     (write _test-input-stream "fn foo x: t {\n")
 3227     (write _test-input-stream "}\n")
 3228     (write _test-input-stream "type t {\n")
 3229     (write _test-input-stream "  x: int\n")
 3230     (write _test-input-stream "  y: int\n")
 3231     (write _test-input-stream "}\n")
 3232     # convert
 3233     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3234     (flush _test-output-buffered-file)
 3235 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3241     # check output
 3242     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 3243     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 3244     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 3245     (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")
 3246     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 3247     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 3248     # var a
 3249     (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")
 3250     (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")
 3251     # foo a
 3252     (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")
 3253     #
 3254     (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")
 3255     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 3256     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 3257     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 3258     (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")
 3259     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 3260     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 3261     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 3262     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 3263     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 3264     (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")
 3265     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 3266     (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")
 3267     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 3268     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 3269     # . epilogue
 3270     89/<- %esp 5/r32/ebp
 3271     5d/pop-to-ebp
 3272     c3/return
 3273 
 3274 # we don't have special support for call-by-reference; just explicitly create
 3275 # a new variable with the address of the arg
 3276 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 3277     # . prologue
 3278     55/push-ebp
 3279     89/<- %ebp 4/r32/esp
 3280     # setup
 3281     (clear-stream _test-input-stream)
 3282     (clear-stream $_test-input-buffered-file->buffer)
 3283     (clear-stream _test-output-stream)
 3284     (clear-stream $_test-output-buffered-file->buffer)
 3285     #
 3286     (write _test-input-stream "fn f {\n")
 3287     (write _test-input-stream "  var a: t\n")
 3288     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 3289     (write _test-input-stream "  foo b\n")
 3290     (write _test-input-stream "}\n")
 3291     (write _test-input-stream "fn foo x: (addr t) {\n")
 3292     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 3293     (write _test-input-stream "  increment *x\n")
 3294     (write _test-input-stream "}\n")
 3295     (write _test-input-stream "type t {\n")
 3296     (write _test-input-stream "  x: int\n")
 3297     (write _test-input-stream "  y: int\n")
 3298     (write _test-input-stream "}\n")
 3299     # convert
 3300     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3301     (flush _test-output-buffered-file)
 3302 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3308     # check output
 3309     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 3310     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 3311     (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")
 3312     (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")
 3313     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 3314     (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")
 3315     # var a: t
 3316     (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")
 3317     (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")
 3318     # var b/eax: (addr t)
 3319     (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")
 3320     (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")
 3321     # foo a
 3322     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 3323     #
 3324     (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")
 3325     (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")
 3326     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 3327     (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")
 3328     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 3329     (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")
 3330     (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")
 3331     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 3332     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 3333     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 3334     (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")
 3335     (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")
 3336     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 3337     (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")
 3338     (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")
 3339     (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")
 3340     (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")
 3341     (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")
 3342     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 3343     (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")
 3344     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 3345     (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")
 3346     (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")
 3347     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 3348     # . epilogue
 3349     89/<- %esp 5/r32/ebp
 3350     5d/pop-to-ebp
 3351     c3/return
 3352 
 3353 test-convert-get-on-local-variable:
 3354     # . prologue
 3355     55/push-ebp
 3356     89/<- %ebp 4/r32/esp
 3357     # setup
 3358     (clear-stream _test-input-stream)
 3359     (clear-stream $_test-input-buffered-file->buffer)
 3360     (clear-stream _test-output-stream)
 3361     (clear-stream $_test-output-buffered-file->buffer)
 3362     #
 3363     (write _test-input-stream "fn foo {\n")
 3364     (write _test-input-stream "  var a: t\n")
 3365     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3366     (write _test-input-stream "}\n")
 3367     (write _test-input-stream "type t {\n")
 3368     (write _test-input-stream "  x: int\n")
 3369     (write _test-input-stream "  y: int\n")
 3370     (write _test-input-stream "}\n")
 3371     # convert
 3372     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3373     (flush _test-output-buffered-file)
 3374 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3380     # check output
 3381     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 3382     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 3383     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 3384     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 3385     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 3386     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 3387     # var a
 3388     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 3389     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 3390     # var c
 3391     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 3392     # get
 3393     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 3394     # reclaim c
 3395     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 3396     # reclaim a
 3397     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 3398     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 3399     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 3400     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 3401     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 3402     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 3403     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 3404     # . epilogue
 3405     89/<- %esp 5/r32/ebp
 3406     5d/pop-to-ebp
 3407     c3/return
 3408 
 3409 test-convert-get-on-function-argument:
 3410     # . prologue
 3411     55/push-ebp
 3412     89/<- %ebp 4/r32/esp
 3413     # setup
 3414     (clear-stream _test-input-stream)
 3415     (clear-stream $_test-input-buffered-file->buffer)
 3416     (clear-stream _test-output-stream)
 3417     (clear-stream $_test-output-buffered-file->buffer)
 3418     #
 3419     (write _test-input-stream "fn foo a: t {\n")
 3420     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3421     (write _test-input-stream "}\n")
 3422     (write _test-input-stream "type t {\n")
 3423     (write _test-input-stream "  x: int\n")
 3424     (write _test-input-stream "  y: int\n")
 3425     (write _test-input-stream "}\n")
 3426     # convert
 3427     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3428     (flush _test-output-buffered-file)
 3429 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3435     # check output
 3436     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 3437     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 3438     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 3439     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 3440     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 3441     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 3442     # var c
 3443     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 3444     # get
 3445     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 3446     # reclaim c
 3447     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 3448     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 3449     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 3450     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 3451     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 3452     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 3453     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 3454     # . epilogue
 3455     89/<- %esp 5/r32/ebp
 3456     5d/pop-to-ebp
 3457     c3/return
 3458 
 3459 test-convert-get-on-function-argument-with-known-type:
 3460     # . prologue
 3461     55/push-ebp
 3462     89/<- %ebp 4/r32/esp
 3463     # setup
 3464     (clear-stream _test-input-stream)
 3465     (clear-stream $_test-input-buffered-file->buffer)
 3466     (clear-stream _test-output-stream)
 3467     (clear-stream $_test-output-buffered-file->buffer)
 3468     #
 3469     (write _test-input-stream "type t {\n")
 3470     (write _test-input-stream "  x: int\n")
 3471     (write _test-input-stream "  y: int\n")
 3472     (write _test-input-stream "}\n")
 3473     (write _test-input-stream "fn foo a: t {\n")
 3474     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3475     (write _test-input-stream "}\n")
 3476     # convert
 3477     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3478     (flush _test-output-buffered-file)
 3479 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3485     # check output
 3486     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 3487     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 3488     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 3489     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 3490     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 3491     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 3492     # var c
 3493     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 3494     # get
 3495     (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")
 3496     # reclaim c
 3497     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 3498     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 3499     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 3500     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 3501     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 3502     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 3503     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 3504     # . epilogue
 3505     89/<- %esp 5/r32/ebp
 3506     5d/pop-to-ebp
 3507     c3/return
 3508 
 3509 test-convert-array-of-user-defined-types:
 3510     # . prologue
 3511     55/push-ebp
 3512     89/<- %ebp 4/r32/esp
 3513     # setup
 3514     (clear-stream _test-input-stream)
 3515     (clear-stream $_test-input-buffered-file->buffer)
 3516     (clear-stream _test-output-stream)
 3517     (clear-stream $_test-output-buffered-file->buffer)
 3518     #
 3519     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3520     (write _test-input-stream "  x: int\n")
 3521     (write _test-input-stream "  y: int\n")
 3522     (write _test-input-stream "}\n")
 3523     (write _test-input-stream "fn foo {\n")
 3524     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3525     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3526     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3527     (write _test-input-stream "}\n")
 3528     # convert
 3529     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3530     (flush _test-output-buffered-file)
 3531 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3537     # check output
 3538     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 3539     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 3540     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 3541     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 3542     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 3543     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 3544     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 3545     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 3546     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 3547     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 3548     (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")
 3549     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 3550     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 3551     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 3552     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 3553     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 3554     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 3555     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 3556     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 3557     # . epilogue
 3558     89/<- %esp 5/r32/ebp
 3559     5d/pop-to-ebp
 3560     c3/return
 3561 
 3562 test-convert-length-of-array-of-user-defined-types-to-eax:
 3563     # . prologue
 3564     55/push-ebp
 3565     89/<- %ebp 4/r32/esp
 3566     # setup
 3567     (clear-stream _test-input-stream)
 3568     (clear-stream $_test-input-buffered-file->buffer)
 3569     (clear-stream _test-output-stream)
 3570     (clear-stream $_test-output-buffered-file->buffer)
 3571     #
 3572     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3573     (write _test-input-stream "  x: int\n")
 3574     (write _test-input-stream "  y: int\n")
 3575     (write _test-input-stream "  z: int\n")
 3576     (write _test-input-stream "}\n")
 3577     (write _test-input-stream "fn foo {\n")
 3578     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3579     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 3580     (write _test-input-stream "}\n")
 3581     # convert
 3582     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3583     (flush _test-output-buffered-file)
 3584 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3590     # check output
 3591     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 3592     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 3593     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 3594     (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")
 3595     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 3596     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 3597     # var arr
 3598     (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")
 3599     (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")
 3600     # length instruction
 3601     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 3602     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 3603     (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")
 3604     (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")
 3605     (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")
 3606     (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")
 3607     (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")
 3608     (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")
 3609     # reclaim arr
 3610     (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")
 3611     #
 3612     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 3613     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 3614     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 3615     (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")
 3616     (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")
 3617     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 3618     # . epilogue
 3619     89/<- %esp 5/r32/ebp
 3620     5d/pop-to-ebp
 3621     c3/return
 3622 
 3623 test-convert-length-of-array-of-user-defined-types-to-ecx:
 3624     # . prologue
 3625     55/push-ebp
 3626     89/<- %ebp 4/r32/esp
 3627     # setup
 3628     (clear-stream _test-input-stream)
 3629     (clear-stream $_test-input-buffered-file->buffer)
 3630     (clear-stream _test-output-stream)
 3631     (clear-stream $_test-output-buffered-file->buffer)
 3632     #
 3633     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3634     (write _test-input-stream "  x: int\n")
 3635     (write _test-input-stream "  y: int\n")
 3636     (write _test-input-stream "  z: int\n")
 3637     (write _test-input-stream "}\n")
 3638     (write _test-input-stream "fn foo {\n")
 3639     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3640     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 3641     (write _test-input-stream "}\n")
 3642     # convert
 3643     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3644     (flush _test-output-buffered-file)
 3645 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3651     # check output
 3652     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 3653     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 3654     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 3655     (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")
 3656     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 3657     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 3658     # var a
 3659     (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")
 3660     (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")
 3661     # var x
 3662     (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")
 3663     # length instruction
 3664     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 3665     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 3666     (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")
 3667     (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")
 3668     (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")
 3669     (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")
 3670     (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")
 3671     (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")
 3672     (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")
 3673     # reclaim x
 3674     (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")
 3675     # reclaim a
 3676     (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")
 3677     #
 3678     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 3679     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 3680     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 3681     (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")
 3682     (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")
 3683     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 3684     # . epilogue
 3685     89/<- %esp 5/r32/ebp
 3686     5d/pop-to-ebp
 3687     c3/return
 3688 
 3689 test-convert-length-of-array-of-user-defined-types-to-edx:
 3690     # . prologue
 3691     55/push-ebp
 3692     89/<- %ebp 4/r32/esp
 3693     # setup
 3694     (clear-stream _test-input-stream)
 3695     (clear-stream $_test-input-buffered-file->buffer)
 3696     (clear-stream _test-output-stream)
 3697     (clear-stream $_test-output-buffered-file->buffer)
 3698     #
 3699     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3700     (write _test-input-stream "  x: int\n")
 3701     (write _test-input-stream "  y: int\n")
 3702     (write _test-input-stream "  z: int\n")
 3703     (write _test-input-stream "}\n")
 3704     (write _test-input-stream "fn foo {\n")
 3705     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3706     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 3707     (write _test-input-stream "}\n")
 3708     # convert
 3709     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3710     (flush _test-output-buffered-file)
 3711 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3717     # check output
 3718     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 3719     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 3720     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 3721     (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")
 3722     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 3723     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 3724     # var a
 3725     (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")
 3726     (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")
 3727     # var x
 3728     (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")
 3729     # length instruction
 3730     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 3731     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 3732     (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")
 3733     (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")
 3734     (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")
 3735     (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")
 3736     (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")
 3737     (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")
 3738     (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")
 3739     # reclaim x
 3740     (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")
 3741     # reclaim a
 3742     (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")
 3743     #
 3744     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 3745     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 3746     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 3747     (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")
 3748     (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")
 3749     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 3750     # . epilogue
 3751     89/<- %esp 5/r32/ebp
 3752     5d/pop-to-ebp
 3753     c3/return
 3754 
 3755 test-convert-length-of-array-of-user-defined-types:
 3756     # . prologue
 3757     55/push-ebp
 3758     89/<- %ebp 4/r32/esp
 3759     # setup
 3760     (clear-stream _test-input-stream)
 3761     (clear-stream $_test-input-buffered-file->buffer)
 3762     (clear-stream _test-output-stream)
 3763     (clear-stream $_test-output-buffered-file->buffer)
 3764     #
 3765     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3766     (write _test-input-stream "  x: int\n")
 3767     (write _test-input-stream "  y: int\n")
 3768     (write _test-input-stream "  z: int\n")
 3769     (write _test-input-stream "}\n")
 3770     (write _test-input-stream "fn foo {\n")
 3771     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3772     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 3773     (write _test-input-stream "}\n")
 3774     # convert
 3775     (convert-mu _test-input-buffered-file _test-output-buffered-file)
 3776     (flush _test-output-buffered-file)
 3777 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
 3783     # check output
 3784     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 3785     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 3786     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 3787     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 3788     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 3789     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 3790     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 3791     (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")
 3792     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 3793     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 3794     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 3795     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 3796     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 3797     (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")
 3798     (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")
 3799     (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")
 3800     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 3801     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 3802     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 3803     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 3804     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 3805     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 3806     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 3807     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 3808     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 3809     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 3810     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 3811     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 3812     # . epilogue
 3813     89/<- %esp 5/r32/ebp
 3814     5d/pop-to-ebp
 3815     c3/return
 3816 
 3817 #######################################################
 3818 # Parsing
 3819 #######################################################
 3820 
 3821 parse-mu:  # in: (addr buffered-file)
 3822     # pseudocode
 3823     #   var curr-function: (addr handle function) = Program->functions
 3824     #   var curr-type: (addr handle typeinfo) = Program->types
 3825     #   var line: (stream byte 512)
 3826     #   var word-slice: slice
 3827     #   while true                                  # line loop
 3828     #     clear-stream(line)
 3829     #     read-line-buffered(in, line)
 3830     #     if (line->write == 0) break               # end of file
 3831     #     word-slice = next-mu-token(line)
 3832     #     if slice-empty?(word-slice)               # end of line
 3833     #       continue
 3834     #     else if slice-starts-with?(word-slice, "#")  # comment
 3835     #       continue                                # end of line
 3836     #     else if slice-equal?(word-slice, "fn")
 3837     #       var new-function: (handle function) = allocate(function)
 3838     #       var vars: (stack live-var 256)
 3839     #       populate-mu-function-header(line, new-function, vars)
 3840     #       populate-mu-function-body(in, new-function, vars)
 3841     #       assert(vars->top == 0)
 3842     #       *curr-function = new-function
 3843     #       curr-function = &new-function->next
 3844     #     else if slice-equal?(word-slice, "type")
 3845     #       word-slice = next-mu-token(line)
 3846     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 3847     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 3848     #       assert(next-word(line) == "{")
 3849     #       populate-mu-type(in, new-type)
 3850     #     else
 3851     #       abort()
 3852     #
 3853     # . prologue
 3854     55/push-ebp
 3855     89/<- %ebp 4/r32/esp
 3856     # . save registers
 3857     50/push-eax
 3858     51/push-ecx
 3859     52/push-edx
 3860     53/push-ebx
 3861     56/push-esi
 3862     57/push-edi
 3863     # var line/ecx: (stream byte 512)
 3864     81 5/subop/subtract %esp 0x200/imm32
 3865     68/push 0x200/imm32/size
 3866     68/push 0/imm32/read
 3867     68/push 0/imm32/write
 3868     89/<- %ecx 4/r32/esp
 3869     # var word-slice/edx: slice
 3870     68/push 0/imm32/end
 3871     68/push 0/imm32/start
 3872     89/<- %edx 4/r32/esp
 3873     # var curr-function/edi: (addr handle function)
 3874     bf/copy-to-edi _Program-functions/imm32
 3875     # var vars/ebx: (stack live-var 256)
 3876     81 5/subop/subtract %esp 0xc00/imm32
 3877     68/push 0xc00/imm32/size
 3878     68/push 0/imm32/top
 3879     89/<- %ebx 4/r32/esp
 3880     {
 3881 $parse-mu:line-loop:
 3882       (clear-stream %ecx)
 3883       (read-line-buffered *(ebp+8) %ecx)
 3884       # if (line->write == 0) break
 3885       81 7/subop/compare *ecx 0/imm32
 3886       0f 84/jump-if-= break/disp32
 3887 +--  6 lines: #?       # dump line -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 3893       (next-mu-token %ecx %edx)
 3894       # if slice-empty?(word-slice) continue
 3895       (slice-empty? %edx)  # => eax
 3896       3d/compare-eax-and 0/imm32/false
 3897       0f 85/jump-if-!= loop/disp32
 3898       # if (*word-slice->start == "#") continue
 3899       # . eax = *word-slice->start
 3900       8b/-> *edx 0/r32/eax
 3901       8a/copy-byte *eax 0/r32/AL
 3902       81 4/subop/and %eax 0xff/imm32
 3903       # . if (eax == '#') continue
 3904       3d/compare-eax-and 0x23/imm32/hash
 3905       0f 84/jump-if-= loop/disp32
 3906       # if (slice-equal?(word-slice, "fn")) parse a function
 3907       {
 3908 $parse-mu:fn:
 3909         (slice-equal? %edx "fn")  # => eax
 3910         3d/compare-eax-and 0/imm32/false
 3911         0f 84/jump-if-= break/disp32
 3912         # var new-function/esi: (handle function)
 3913         68/push 0/imm32
 3914         68/push 0/imm32
 3915         89/<- %esi 4/r32/esp
 3916         # populate-mu-function(line, in, vars, new-function)
 3917         (allocate Heap *Function-size %esi)
 3918         # var new-function-addr/eax: (addr function)
 3919         (lookup *esi *(esi+4))  # => eax
 3920         (clear-stack %ebx)
 3921         (populate-mu-function-header %ecx %eax %ebx)
 3922         (populate-mu-function-body *(ebp+8) %eax %ebx)
 3923         # *curr-function = new-function
 3924         8b/-> *esi 0/r32/eax
 3925         89/<- *edi 0/r32/eax
 3926         8b/-> *(esi+4) 0/r32/eax
 3927         89/<- *(edi+4) 0/r32/eax
 3928         # curr-function = &new-function->next
 3929         # . var tmp/eax: (addr function) = lookup(new-function)
 3930         (lookup *esi *(esi+4))  # => eax
 3931         # . curr-function = &tmp->next
 3932         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 3933         # reclaim new-function
 3934         81 0/subop/add %esp 8/imm32
 3935         #
 3936         e9/jump $parse-mu:line-loop/disp32
 3937       }
 3938       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 3939       {
 3940 $parse-mu:type:
 3941         (slice-equal? %edx "type")  # => eax
 3942         3d/compare-eax-and 0/imm32
 3943         0f 84/jump-if-= break/disp32
 3944         (next-mu-token %ecx %edx)
 3945         # var type-id/eax: int
 3946         (pos-or-insert-slice Type-id %edx)  # => eax
 3947         # spill
 3948         51/push-ecx
 3949         # var new-type/ecx: (handle typeinfo)
 3950         68/push 0/imm32
 3951         68/push 0/imm32
 3952         89/<- %ecx 4/r32/esp
 3953         (find-or-create-typeinfo %eax %ecx)
 3954         #
 3955         (lookup *ecx *(ecx+4))  # => eax
 3956         # TODO: ensure that 'line' has nothing else but '{'
 3957 #? (dump-typeinfos "=== aaa\n")
 3958         (populate-mu-type *(ebp+8) %eax)  # => eax
 3959 #? (dump-typeinfos "=== zzz\n")
 3960         # reclaim new-type
 3961         81 0/subop/add %esp 8/imm32
 3962         # restore
 3963         59/pop-to-ecx
 3964         e9/jump $parse-mu:line-loop/disp32
 3965       }
 3966       # otherwise abort
 3967       e9/jump $parse-mu:error1/disp32
 3968     } # end line loop
 3969 $parse-mu:end:
 3970     # . reclaim locals
 3971     81 0/subop/add %esp 0xe1c/imm32
 3972     # . restore registers
 3973     5f/pop-to-edi
 3974     5e/pop-to-esi
 3975     5b/pop-to-ebx
 3976     5a/pop-to-edx
 3977     59/pop-to-ecx
 3978     58/pop-to-eax
 3979     # . epilogue
 3980     89/<- %esp 5/r32/ebp
 3981     5d/pop-to-ebp
 3982     c3/return
 3983 
 3984 $parse-mu:error1:
 3985     # error("unexpected top-level command: " word-slice "\n")
 3986     (write-buffered Stderr "unexpected top-level command: ")
 3987     (write-slice-buffered Stderr %edx)
 3988     (write-buffered Stderr "\n")
 3989     (flush Stderr)
 3990     # . syscall(exit, 1)
 3991     bb/copy-to-ebx  1/imm32
 3992     b8/copy-to-eax  1/imm32/exit
 3993     cd/syscall  0x80/imm8
 3994     # never gets here
 3995 
 3996 $parse-mu:error2:
 3997     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 3998     (print-int32-buffered Stderr *ebx)
 3999     (write-buffered Stderr " vars not reclaimed after fn '")
 4000     (write-slice-buffered Stderr *eax)  # Function-name
 4001     (write-buffered Stderr "'\n")
 4002     (flush Stderr)
 4003     # . syscall(exit, 1)
 4004     bb/copy-to-ebx  1/imm32
 4005     b8/copy-to-eax  1/imm32/exit
 4006     cd/syscall  0x80/imm8
 4007     # never gets here
 4008 
 4009 # scenarios considered:
 4010 # ✗ fn foo  # no block
 4011 # ✓ fn foo {
 4012 # ✗ fn foo { {
 4013 # ✗ fn foo { }
 4014 # ✗ fn foo { } {
 4015 # ✗ fn foo x {
 4016 # ✗ fn foo x: {
 4017 # ✓ fn foo x: int {
 4018 # ✓ fn foo x: int {
 4019 # ✓ fn foo x: int -> y/eax: int {
 4020 populate-mu-function-header:  # first-line: (addr stream byte), out: (addr function), vars: (addr stack live-var)
 4021     # pseudocode:
 4022     #   var name: slice
 4023     #   next-mu-token(first-line, name)
 4024     #   assert(name not in '{' '}' '->')
 4025     #   out->name = slice-to-string(name)
 4026     #   ## inouts
 4027     #   while true
 4028     #     ## name
 4029     #     name = next-mu-token(first-line)
 4030     #     if (name == '{') goto done
 4031     #     if (name == '->') break
 4032     #     assert(name != '}')
 4033     #     var v: (handle var) = parse-var-with-type(name, first-line)
 4034     #     assert(v->register == null)
 4035     #     # v->block-depth is implicitly 0
 4036     #     out->inouts = append(v, out->inouts)
 4037     #     push(vars, {v, false})
 4038     #   ## outputs
 4039     #   while true
 4040     #     ## name
 4041     #     name = next-mu-token(first-line)
 4042     #     assert(name not in '{' '}' '->')
 4043     #     var v: (handle var) = parse-var-with-type(name, first-line)
 4044     #     assert(v->register != null)
 4045     #     out->outputs = append(v, out->outputs)
 4046     #   done:
 4047     #
 4048     # . prologue
 4049     55/push-ebp
 4050     89/<- %ebp 4/r32/esp
 4051     # . save registers
 4052     50/push-eax
 4053     51/push-ecx
 4054     52/push-edx
 4055     53/push-ebx
 4056     57/push-edi
 4057     # edi = out
 4058     8b/-> *(ebp+0xc) 7/r32/edi
 4059     # var word-slice/ecx: slice
 4060     68/push 0/imm32/end
 4061     68/push 0/imm32/start
 4062     89/<- %ecx 4/r32/esp
 4063     # var v/ebx: (handle var)
 4064     68/push 0/imm32
 4065     68/push 0/imm32
 4066     89/<- %ebx 4/r32/esp
 4067     # read function name
 4068     (next-mu-token *(ebp+8) %ecx)
 4069     # error checking
 4070     # TODO: error if name starts with 'break' or 'loop'
 4071     # if (word-slice == '{') abort
 4072     (slice-equal? %ecx "{")   # => eax
 4073     3d/compare-eax-and 0/imm32/false
 4074     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4075     # if (word-slice == '->') abort
 4076     (slice-equal? %ecx "->")   # => eax
 4077     3d/compare-eax-and 0/imm32/false
 4078     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4079     # if (word-slice == '}') abort
 4080     (slice-equal? %ecx "}")   # => eax
 4081     3d/compare-eax-and 0/imm32/false
 4082     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4083     # save function name
 4084     (slice-to-string Heap %ecx %edi)  # Function-name
 4085     # save function inouts
 4086     {
 4087 $populate-mu-function-header:check-for-inout:
 4088       (next-mu-token *(ebp+8) %ecx)
 4089       # if (word-slice == '{') goto done
 4090       (slice-equal? %ecx "{")   # => eax
 4091       3d/compare-eax-and 0/imm32/false
 4092       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 4093       # if (word-slice == '->') break
 4094       (slice-equal? %ecx "->")   # => eax
 4095       3d/compare-eax-and 0/imm32/false
 4096       0f 85/jump-if-!= break/disp32
 4097       # if (word-slice == '}') abort
 4098       (slice-equal? %ecx "}")   # => eax
 4099       3d/compare-eax-and 0/imm32/false
 4100       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4101       # v = parse-var-with-type(word-slice, first-line)
 4102       (parse-var-with-type %ecx *(ebp+8) %ebx)
 4103       # assert(v->register == null)
 4104       # . eax: (addr var) = lookup(v)
 4105       (lookup *ebx *(ebx+4))  # => eax
 4106       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 4107       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 4108       # v->block-depth is implicitly 0
 4109       #
 4110       # out->inouts = append(v, out->inouts)
 4111       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 4112       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 4113       # push(vars, {v, false})
 4114       (push *(ebp+0x10) *ebx)
 4115       (push *(ebp+0x10) *(ebx+4))
 4116       (push *(ebp+0x10) 0)  # false
 4117       #
 4118       e9/jump loop/disp32
 4119     }
 4120     # save function outputs
 4121     {
 4122 $populate-mu-function-header:check-for-out:
 4123       (next-mu-token *(ebp+8) %ecx)
 4124       # if (word-slice == '{') break
 4125       (slice-equal? %ecx "{")   # => eax
 4126       3d/compare-eax-and 0/imm32/false
 4127       0f 85/jump-if-!= break/disp32
 4128       # if (word-slice == '->') abort
 4129       (slice-equal? %ecx "->")   # => eax
 4130       3d/compare-eax-and 0/imm32/false
 4131       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4132       # if (word-slice == '}') abort
 4133       (slice-equal? %ecx "}")   # => eax
 4134       3d/compare-eax-and 0/imm32/false
 4135       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4136       # v = parse-var-with-type(word-slice, first-line)
 4137       (parse-var-with-type %ecx *(ebp+8) %ebx)
 4138       # assert(var->register != null)
 4139       # . eax: (addr var) = lookup(v)
 4140       (lookup *ebx *(ebx+4))  # => eax
 4141       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 4142       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 4143       # out->outputs = append(v, out->outputs)
 4144       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 4145       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 4146       #
 4147       e9/jump loop/disp32
 4148     }
 4149 $populate-mu-function-header:done:
 4150     (check-no-tokens-left *(ebp+8))
 4151 $populate-mu-function-header:end:
 4152     # . reclaim locals
 4153     81 0/subop/add %esp 0x10/imm32
 4154     # . restore registers
 4155     5f/pop-to-edi
 4156     5b/pop-to-ebx
 4157     5a/pop-to-edx
 4158     59/pop-to-ecx
 4159     58/pop-to-eax
 4160     # . epilogue
 4161     89/<- %esp 5/r32/ebp
 4162     5d/pop-to-ebp
 4163     c3/return
 4164 
 4165 $populate-mu-function-header:error1:
 4166     # error("function header not in form 'fn <name> {'")
 4167     (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 4168     (flush Stderr)
 4169     (rewind-stream *(ebp+8))
 4170     (write-stream 2 *(ebp+8))
 4171     (write-buffered Stderr "'\n")
 4172     (flush Stderr)
 4173     # . syscall(exit, 1)
 4174     bb/copy-to-ebx  1/imm32
 4175     b8/copy-to-eax  1/imm32/exit
 4176     cd/syscall  0x80/imm8
 4177     # never gets here
 4178 
 4179 $populate-mu-function-header:error2:
 4180     # error("function input '" var "' cannot be in a register")
 4181     (write-buffered Stderr "function input '")
 4182     (write-buffered Stderr *ebx)  # Var-name
 4183     (write-buffered Stderr "' cannot be in a register")
 4184     (flush Stderr)
 4185     # . syscall(exit, 1)
 4186     bb/copy-to-ebx  1/imm32
 4187     b8/copy-to-eax  1/imm32/exit
 4188     cd/syscall  0x80/imm8
 4189     # never gets here
 4190 
 4191 $populate-mu-function-header:error3:
 4192     # error("function input '" var "' must be in a register")
 4193     (write-buffered Stderr "function input '")
 4194     (lookup *ebx *(ebx+4))  # => eax
 4195     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 4196     (write-buffered Stderr %eax)
 4197     (write-buffered Stderr "' must be in a register, in instruction '")
 4198     (flush Stderr)
 4199     (rewind-stream *(ebp+8))
 4200     (write-stream 2 *(ebp+8))
 4201     (write-buffered Stderr "'\n")
 4202     (flush Stderr)
 4203     # . syscall(exit, 1)
 4204     bb/copy-to-ebx  1/imm32
 4205     b8/copy-to-eax  1/imm32/exit
 4206     cd/syscall  0x80/imm8
 4207     # never gets here
 4208 
 4209 test-function-header-with-arg:
 4210     # . prologue
 4211     55/push-ebp
 4212     89/<- %ebp 4/r32/esp
 4213     # setup
 4214     (clear-stream _test-input-stream)
 4215     (write _test-input-stream "foo n: int {\n")
 4216     # var result/ecx: function
 4217     2b/subtract *Function-size 4/r32/esp
 4218     89/<- %ecx 4/r32/esp
 4219     (zero-out %ecx *Function-size)
 4220     # var vars/ebx: (stack live-var 16)
 4221     81 5/subop/subtract %esp 0xc0/imm32
 4222     68/push 0xc0/imm32/size
 4223     68/push 0/imm32/top
 4224     89/<- %ebx 4/r32/esp
 4225     # convert
 4226     (populate-mu-function-header _test-input-stream %ecx %ebx)
 4227     # check result->name
 4228     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4229     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 4230     # var v/edx: (addr var) = result->inouts->value
 4231     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4232     (lookup *eax *(eax+4))  # List-value List-value => eax
 4233     89/<- %edx 0/r32/eax
 4234     # check v->name
 4235     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4236     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 4237     # check v->type
 4238     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4239     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 4240     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 4241     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 4242     # . epilogue
 4243     89/<- %esp 5/r32/ebp
 4244     5d/pop-to-ebp
 4245     c3/return
 4246 
 4247 test-function-header-with-multiple-args:
 4248     # . prologue
 4249     55/push-ebp
 4250     89/<- %ebp 4/r32/esp
 4251     # setup
 4252     (clear-stream _test-input-stream)
 4253     (write _test-input-stream "foo a: int, b: int c: int {\n")
 4254     # result/ecx: function
 4255     2b/subtract *Function-size 4/r32/esp
 4256     89/<- %ecx 4/r32/esp
 4257     (zero-out %ecx *Function-size)
 4258     # var vars/ebx: (stack live-var 16)
 4259     81 5/subop/subtract %esp 0xc0/imm32
 4260     68/push 0xc0/imm32/size
 4261     68/push 0/imm32/top
 4262     89/<- %ebx 4/r32/esp
 4263     # convert
 4264     (populate-mu-function-header _test-input-stream %ecx %ebx)
 4265     # check result->name
 4266     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4267     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 4268     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4269     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4270     89/<- %edx 0/r32/eax
 4271 $test-function-header-with-multiple-args:inout0:
 4272     # var v/ebx: (addr var) = lookup(inouts->value)
 4273     (lookup *edx *(edx+4))  # List-value List-value => eax
 4274     89/<- %ebx 0/r32/eax
 4275     # check v->name
 4276     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4277     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 4278     # check v->type
 4279     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4280     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 4281     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 4282     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 4283 $test-function-header-with-multiple-args:inout1:
 4284     # inouts = lookup(inouts->next)
 4285     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4286     89/<- %edx 0/r32/eax
 4287     # v = lookup(inouts->value)
 4288     (lookup *edx *(edx+4))  # List-value List-value => eax
 4289     89/<- %ebx 0/r32/eax
 4290     # check v->name
 4291     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4292     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 4293     # check v->type
 4294     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4295     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 4296     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 4297     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 4298 $test-function-header-with-multiple-args:inout2:
 4299     # inouts = lookup(inouts->next)
 4300     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4301     89/<- %edx 0/r32/eax
 4302     # v = lookup(inouts->value)
 4303     (lookup *edx *(edx+4))  # List-value List-value => eax
 4304     89/<- %ebx 0/r32/eax
 4305     # check v->name
 4306     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4307     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 4308     # check v->type
 4309     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4310     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 4311     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 4312     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 4313     # . epilogue
 4314     89/<- %esp 5/r32/ebp
 4315     5d/pop-to-ebp
 4316     c3/return
 4317 
 4318 test-function-header-with-multiple-args-and-outputs:
 4319     # . prologue
 4320     55/push-ebp
 4321     89/<- %ebp 4/r32/esp
 4322     # setup
 4323     (clear-stream _test-input-stream)
 4324     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 4325     # result/ecx: function
 4326     2b/subtract *Function-size 4/r32/esp
 4327     89/<- %ecx 4/r32/esp
 4328     (zero-out %ecx *Function-size)
 4329     # var vars/ebx: (stack live-var 16)
 4330     81 5/subop/subtract %esp 0xc0/imm32
 4331     68/push 0xc0/imm32/size
 4332     68/push 0/imm32/top
 4333     89/<- %ebx 4/r32/esp
 4334     # convert
 4335     (populate-mu-function-header _test-input-stream %ecx %ebx)
 4336     # check result->name
 4337     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4338     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 4339     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4340     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4341     89/<- %edx 0/r32/eax
 4342 $test-function-header-with-multiple-args-and-outputs:inout0:
 4343     # var v/ebx: (addr var) = lookup(inouts->value)
 4344     (lookup *edx *(edx+4))  # List-value List-value => eax
 4345     89/<- %ebx 0/r32/eax
 4346     # check v->name
 4347     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4348     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 4349     # check v->type
 4350     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4351     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 4352     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 4353     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 4354 $test-function-header-with-multiple-args-and-outputs:inout1:
 4355     # inouts = lookup(inouts->next)
 4356     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4357     89/<- %edx 0/r32/eax
 4358     # v = lookup(inouts->value)
 4359     (lookup *edx *(edx+4))  # List-value List-value => eax
 4360     89/<- %ebx 0/r32/eax
 4361     # check v->name
 4362     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4363     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 4364     # check v->type
 4365     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4366     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 4367     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 4368     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 4369 $test-function-header-with-multiple-args-and-outputs:inout2:
 4370     # inouts = lookup(inouts->next)
 4371     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4372     89/<- %edx 0/r32/eax
 4373     # v = lookup(inouts->value)
 4374     (lookup *edx *(edx+4))  # List-value List-value => eax
 4375     89/<- %ebx 0/r32/eax
 4376     # check v->name
 4377     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4378     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 4379     # check v->type
 4380     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4381     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 4382     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 4383     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 4384 $test-function-header-with-multiple-args-and-outputs:out0:
 4385     # var outputs/edx: (addr list var) = lookup(result->outputs)
 4386     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 4387     89/<- %edx 0/r32/eax
 4388     # v = lookup(outputs->value)
 4389     (lookup *edx *(edx+4))  # List-value List-value => eax
 4390     89/<- %ebx 0/r32/eax
 4391     # check v->name
 4392     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4393     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 4394     # check v->register
 4395     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4396     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 4397     # check v->type
 4398     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4399     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 4400     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 4401     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 4402 $test-function-header-with-multiple-args-and-outputs:out1:
 4403     # outputs = lookup(outputs->next)
 4404     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4405     89/<- %edx 0/r32/eax
 4406     # v = lookup(inouts->value)
 4407     (lookup *edx *(edx+4))  # List-value List-value => eax
 4408     89/<- %ebx 0/r32/eax
 4409     # check v->name
 4410     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4411     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 4412     # check v->register
 4413     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4414     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 4415     # check v->type
 4416     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4417     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 4418     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 4419     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 4420     # . epilogue
 4421     89/<- %esp 5/r32/ebp
 4422     5d/pop-to-ebp
 4423     c3/return
 4424 
 4425 # format for variables with types
 4426 #   x: int
 4427 #   x: int,
 4428 #   x/eax: int
 4429 #   x/eax: int,
 4430 # ignores at most one trailing comma
 4431 # WARNING: modifies name
 4432 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var)
 4433     # pseudocode:
 4434     #   var s: slice
 4435     #   if (!slice-ends-with(name, ":"))
 4436     #     abort
 4437     #   --name->end to skip ':'
 4438     #   next-token-from-slice(name->start, name->end, '/', s)
 4439     #   new-var-from-slice(s, out)
 4440     #   ## register
 4441     #   next-token-from-slice(s->end, name->end, '/', s)
 4442     #   if (!slice-empty?(s))
 4443     #     out->register = slice-to-string(s)
 4444     #   ## type
 4445     #   var type: (handle tree type-id) = parse-type(first-line)
 4446     #   out->type = type
 4447     #
 4448     # . prologue
 4449     55/push-ebp
 4450     89/<- %ebp 4/r32/esp
 4451     # . save registers
 4452     50/push-eax
 4453     51/push-ecx
 4454     52/push-edx
 4455     53/push-ebx
 4456     56/push-esi
 4457     57/push-edi
 4458     # esi = name
 4459     8b/-> *(ebp+8) 6/r32/esi
 4460     # if (!slice-ends-with?(name, ":")) abort
 4461     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 4462     49/decrement-ecx
 4463     8a/copy-byte *ecx 1/r32/CL
 4464     81 4/subop/and %ecx 0xff/imm32
 4465     81 7/subop/compare %ecx 0x3a/imm32/colon
 4466     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 4467     # --name->end to skip ':'
 4468     ff 1/subop/decrement *(esi+4)
 4469     # var s/ecx: slice
 4470     68/push 0/imm32/end
 4471     68/push 0/imm32/start
 4472     89/<- %ecx 4/r32/esp
 4473 $parse-var-with-type:parse-name:
 4474     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 4475 $parse-var-with-type:create-var:
 4476     # new-var-from-slice(s, out)
 4477     (new-var-from-slice Heap %ecx *(ebp+0x10))
 4478     # save out->register
 4479 $parse-var-with-type:save-register:
 4480     # . var out-addr/edi: (addr var) = lookup(*out)
 4481     8b/-> *(ebp+0x10) 7/r32/edi
 4482     (lookup *edi *(edi+4))  # => eax
 4483     89/<- %edi 0/r32/eax
 4484     # . s = next-token(...)
 4485     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 4486     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 4487     {
 4488 $parse-var-with-type:write-register:
 4489       (slice-empty? %ecx)  # => eax
 4490       3d/compare-eax-and 0/imm32/false
 4491       75/jump-if-!= break/disp8
 4492       # out->register = slice-to-string(s)
 4493       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 4494       (slice-to-string Heap %ecx %eax)
 4495     }
 4496 $parse-var-with-type:save-type:
 4497     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 4498     (parse-type Heap *(ebp+0xc) %eax)
 4499 $parse-var-with-type:end:
 4500     # . reclaim locals
 4501     81 0/subop/add %esp 8/imm32
 4502     # . restore registers
 4503     5f/pop-to-edi
 4504     5e/pop-to-esi
 4505     5b/pop-to-ebx
 4506     5a/pop-to-edx
 4507     59/pop-to-ecx
 4508     58/pop-to-eax
 4509     # . epilogue
 4510     89/<- %esp 5/r32/ebp
 4511     5d/pop-to-ebp
 4512     c3/return
 4513 
 4514 $parse-var-with-type:abort:
 4515     # error("var should have form 'name: type' in '" line "'\n")
 4516     (write-buffered Stderr "var should have form 'name: type' in '")
 4517     (flush Stderr)
 4518     (rewind-stream *(ebp+0xc))
 4519     (write-stream 2 *(ebp+0xc))
 4520     (write-buffered Stderr "'\n")
 4521     (flush Stderr)
 4522     # . syscall(exit, 1)
 4523     bb/copy-to-ebx  1/imm32
 4524     b8/copy-to-eax  1/imm32/exit
 4525     cd/syscall  0x80/imm8
 4526     # never gets here
 4527 
 4528 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
 4529     # pseudocode:
 4530     #   var s: slice = next-mu-token(in)
 4531     #   assert s != ""
 4532     #   assert s != "->"
 4533     #   assert s != "{"
 4534     #   assert s != "}"
 4535     #   if s == ")"
 4536     #     return
 4537     #   out = allocate(Tree)
 4538     #   if s != "("
 4539     #     HACK: if s is an int, parse and return it
 4540     #     out->left-is-atom? = true
 4541     #     out->value = pos-or-insert-slice(Type-id, s)
 4542     #     return
 4543     #   out->left = parse-type(ad, in)
 4544     #   out->right = parse-type-tree(ad, in)
 4545     #
 4546     # . prologue
 4547     55/push-ebp
 4548     89/<- %ebp 4/r32/esp
 4549     # . save registers
 4550     50/push-eax
 4551     51/push-ecx
 4552     52/push-edx
 4553     # clear out
 4554     (zero-out *(ebp+0x10) *Handle-size)
 4555     # var s/ecx: slice
 4556     68/push 0/imm32
 4557     68/push 0/imm32
 4558     89/<- %ecx 4/r32/esp
 4559     # s = next-mu-token(in)
 4560     (next-mu-token *(ebp+0xc) %ecx)
 4561 #?     (write-buffered Stderr "tok: ")
 4562 #?     (write-slice-buffered Stderr %ecx)
 4563 #?     (write-buffered Stderr "$\n")
 4564 #?     (flush Stderr)
 4565     # assert s != ""
 4566     (slice-equal? %ecx "")  # => eax
 4567     3d/compare-eax-and 0/imm32/false
 4568     0f 85/jump-if-!= $parse-type:abort/disp32
 4569     # assert s != "{"
 4570     (slice-equal? %ecx "{")  # => eax
 4571     3d/compare-eax-and 0/imm32/false
 4572     0f 85/jump-if-!= $parse-type:abort/disp32
 4573     # assert s != "}"
 4574     (slice-equal? %ecx "}")  # => eax
 4575     3d/compare-eax-and 0/imm32/false
 4576     0f 85/jump-if-!= $parse-type:abort/disp32
 4577     # assert s != "->"
 4578     (slice-equal? %ecx "->")  # => eax
 4579     3d/compare-eax-and 0/imm32/false
 4580     0f 85/jump-if-!= $parse-type:abort/disp32
 4581     # if (s == ")") return
 4582     (slice-equal? %ecx ")")  # => eax
 4583     3d/compare-eax-and 0/imm32/false
 4584     0f 85/jump-if-!= $parse-type:end/disp32
 4585     # out = new tree
 4586     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4587     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 4588     8b/-> *(ebp+0x10) 2/r32/edx
 4589     (lookup *edx *(edx+4))  # => eax
 4590     89/<- %edx 0/r32/eax
 4591     {
 4592       # if (s != "(") break
 4593       (slice-equal? %ecx "(")  # => eax
 4594       3d/compare-eax-and 0/imm32/false
 4595       75/jump-if-!= break/disp8
 4596       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 4597       {
 4598 $parse-type:check-for-int:
 4599         (is-hex-int? %ecx)  # => eax
 4600         3d/compare-eax-and 0/imm32/false
 4601         74/jump-if-= break/disp8
 4602 $parse-type:int:
 4603         (parse-hex-int-from-slice %ecx)  # => eax
 4604         89/<- *(edx+4) 0/r32/eax  # Tree-value
 4605         e9/jump $parse-type:end/disp32
 4606       }
 4607 $parse-type:atom:
 4608       # out->left-is-atom? = true
 4609       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 4610       # out->value = pos-or-insert-slice(Type-id, s)
 4611       (pos-or-insert-slice Type-id %ecx)  # => eax
 4612       89/<- *(edx+4) 0/r32/eax  # Tree-value
 4613       e9/jump $parse-type:end/disp32
 4614     }
 4615 $parse-type:non-atom:
 4616     # otherwise s == "("
 4617     # out->left = parse-type(ad, in)
 4618     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 4619     (parse-type *(ebp+8) *(ebp+0xc) %eax)
 4620     # out->right = parse-type-tree(ad, in)
 4621     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4622     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
 4623 $parse-type:end:
 4624     # . reclaim locals
 4625     81 0/subop/add %esp 8/imm32
 4626     # . restore registers
 4627     5a/pop-to-edx
 4628     59/pop-to-ecx
 4629     58/pop-to-eax
 4630     # . epilogue
 4631     89/<- %esp 5/r32/ebp
 4632     5d/pop-to-ebp
 4633     c3/return
 4634 
 4635 $parse-type:abort:
 4636     # error("unexpected token when parsing type: '" s "'\n")
 4637     (write-buffered Stderr "unexpected token when parsing type: '")
 4638     (write-slice-buffered Stderr %ecx)
 4639     (write-buffered Stderr "'\n")
 4640     (flush Stderr)
 4641     # . syscall(exit, 1)
 4642     bb/copy-to-ebx  1/imm32
 4643     b8/copy-to-eax  1/imm32/exit
 4644     cd/syscall  0x80/imm8
 4645     # never gets here
 4646 
 4647 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id)
 4648     # pseudocode:
 4649     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 4650     #   if tmp == 0
 4651     #     return 0
 4652     #   out = allocate(Tree)
 4653     #   out->left = tmp
 4654     #   out->right = parse-type-tree(ad, in)
 4655     #
 4656     # . prologue
 4657     55/push-ebp
 4658     89/<- %ebp 4/r32/esp
 4659     # . save registers
 4660     50/push-eax
 4661     51/push-ecx
 4662     52/push-edx
 4663     #
 4664     (zero-out *(ebp+0x10) *Handle-size)
 4665     # var tmp/ecx: (handle tree type-id)
 4666     68/push 0/imm32
 4667     68/push 0/imm32
 4668     89/<- %ecx 4/r32/esp
 4669     # tmp = parse-type(ad, in)
 4670     (parse-type *(ebp+8) *(ebp+0xc) %ecx)
 4671     # if (tmp == 0) return
 4672     81 7/subop/compare *ecx 0/imm32
 4673     74/jump-if-= $parse-type-tree:end/disp8
 4674     # out = new tree
 4675     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4676     # var out-addr/edx: (addr tree) = lookup(*out)
 4677     8b/-> *(ebp+0x10) 2/r32/edx
 4678     (lookup *edx *(edx+4))  # => eax
 4679     89/<- %edx 0/r32/eax
 4680     # out->left = tmp
 4681     8b/-> *ecx 0/r32/eax
 4682     89/<- *(edx+4) 0/r32/eax  # Tree-left
 4683     8b/-> *(ecx+4) 0/r32/eax
 4684     89/<- *(edx+8) 0/r32/eax  # Tree-left
 4685     # out->right = parse-type-tree(ad, in)
 4686     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4687     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax)
 4688 $parse-type-tree:end:
 4689     # . reclaim locals
 4690     81 0/subop/add %esp 8/imm32
 4691     # . restore registers
 4692     5a/pop-to-edx
 4693     59/pop-to-ecx
 4694     58/pop-to-eax
 4695     # . epilogue
 4696     89/<- %esp 5/r32/ebp
 4697     5d/pop-to-ebp
 4698     c3/return
 4699 
 4700 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 4701     # pseudocode:
 4702     # start:
 4703     #   skip-chars-matching-whitespace(in)
 4704     #   if in->read >= in->write              # end of in
 4705     #     out = {0, 0}
 4706     #     return
 4707     #   out->start = &in->data[in->read]
 4708     #   var curr-byte/eax: byte = in->data[in->read]
 4709     #   if curr->byte == ','                  # comment token
 4710     #     ++in->read
 4711     #     goto start
 4712     #   if curr-byte == '#'                   # comment
 4713     #     goto done                             # treat as eof
 4714     #   if curr-byte == '"'                   # string literal
 4715     #     skip-string(in)
 4716     #     goto done                           # no metadata
 4717     #   if curr-byte == '('
 4718     #     ++in->read
 4719     #     goto done
 4720     #   if curr-byte == ')'
 4721     #     ++in->read
 4722     #     goto done
 4723     #   # read a word
 4724     #   while true
 4725     #     if in->read >= in->write
 4726     #       break
 4727     #     curr-byte = in->data[in->read]
 4728     #     if curr-byte == ' '
 4729     #       break
 4730     #     if curr-byte == '\r'
 4731     #       break
 4732     #     if curr-byte == '\n'
 4733     #       break
 4734     #     if curr-byte == '('
 4735     #       break
 4736     #     if curr-byte == ')'
 4737     #       break
 4738     #     if curr-byte == ','
 4739     #       break
 4740     #     ++in->read
 4741     # done:
 4742     #   out->end = &in->data[in->read]
 4743     #
 4744     # . prologue
 4745     55/push-ebp
 4746     89/<- %ebp 4/r32/esp
 4747     # . save registers
 4748     50/push-eax
 4749     51/push-ecx
 4750     56/push-esi
 4751     57/push-edi
 4752     # esi = in
 4753     8b/-> *(ebp+8) 6/r32/esi
 4754     # edi = out
 4755     8b/-> *(ebp+0xc) 7/r32/edi
 4756 $next-mu-token:start:
 4757     (skip-chars-matching-whitespace %esi)
 4758 $next-mu-token:check0:
 4759     # if (in->read >= in->write) return out = {0, 0}
 4760     # . ecx = in->read
 4761     8b/-> *(esi+4) 1/r32/ecx
 4762     # . if (ecx >= in->write) return out = {0, 0}
 4763     3b/compare<- *esi 1/r32/ecx
 4764     c7 0/subop/copy *edi 0/imm32
 4765     c7 0/subop/copy *(edi+4) 0/imm32
 4766     0f 8d/jump-if->= $next-mu-token:end/disp32
 4767     # out->start = &in->data[in->read]
 4768     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4769     89/<- *edi 0/r32/eax
 4770     # var curr-byte/eax: byte = in->data[in->read]
 4771     31/xor-with %eax 0/r32/eax
 4772     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4773     {
 4774 $next-mu-token:check-for-comma:
 4775       # if (curr-byte != ',') break
 4776       3d/compare-eax-and 0x2c/imm32/comma
 4777       75/jump-if-!= break/disp8
 4778       # ++in->read
 4779       ff 0/subop/increment *(esi+4)
 4780       # restart
 4781       e9/jump $next-mu-token:start/disp32
 4782     }
 4783     {
 4784 $next-mu-token:check-for-comment:
 4785       # if (curr-byte != '#') break
 4786       3d/compare-eax-and 0x23/imm32/pound
 4787       75/jump-if-!= break/disp8
 4788       # return eof
 4789       e9/jump $next-mu-token:done/disp32
 4790     }
 4791     {
 4792 $next-mu-token:check-for-string-literal:
 4793       # if (curr-byte != '"') break
 4794       3d/compare-eax-and 0x22/imm32/dquote
 4795       75/jump-if-!= break/disp8
 4796       (skip-string %esi)
 4797       # return
 4798       e9/jump $next-mu-token:done/disp32
 4799     }
 4800     {
 4801 $next-mu-token:check-for-open-paren:
 4802       # if (curr-byte != '(') break
 4803       3d/compare-eax-and 0x28/imm32/open-paren
 4804       75/jump-if-!= break/disp8
 4805       # ++in->read
 4806       ff 0/subop/increment *(esi+4)
 4807       # return
 4808       e9/jump $next-mu-token:done/disp32
 4809     }
 4810     {
 4811 $next-mu-token:check-for-close-paren:
 4812       # if (curr-byte != ')') break
 4813       3d/compare-eax-and 0x29/imm32/close-paren
 4814       75/jump-if-!= break/disp8
 4815       # ++in->read
 4816       ff 0/subop/increment *(esi+4)
 4817       # return
 4818       e9/jump $next-mu-token:done/disp32
 4819     }
 4820     {
 4821 $next-mu-token:regular-word-without-metadata:
 4822       # if (in->read >= in->write) break
 4823       # . ecx = in->read
 4824       8b/-> *(esi+4) 1/r32/ecx
 4825       # . if (ecx >= in->write) break
 4826       3b/compare<- *esi 1/r32/ecx
 4827       7d/jump-if->= break/disp8
 4828       # var c/eax: byte = in->data[in->read]
 4829       31/xor-with %eax 0/r32/eax
 4830       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4831       # if (c == ' ') break
 4832       3d/compare-eax-and 0x20/imm32/space
 4833       74/jump-if-= break/disp8
 4834       # if (c == '\r') break
 4835       3d/compare-eax-and 0xd/imm32/carriage-return
 4836       74/jump-if-= break/disp8
 4837       # if (c == '\n') break
 4838       3d/compare-eax-and 0xa/imm32/newline
 4839       74/jump-if-= break/disp8
 4840       # if (c == '(') break
 4841       3d/compare-eax-and 0x28/imm32/open-paren
 4842       0f 84/jump-if-= break/disp32
 4843       # if (c == ')') break
 4844       3d/compare-eax-and 0x29/imm32/close-paren
 4845       0f 84/jump-if-= break/disp32
 4846       # if (c == ',') break
 4847       3d/compare-eax-and 0x2c/imm32/comma
 4848       0f 84/jump-if-= break/disp32
 4849       # ++in->read
 4850       ff 0/subop/increment *(esi+4)
 4851       #
 4852       e9/jump loop/disp32
 4853     }
 4854 $next-mu-token:done:
 4855     # out->end = &in->data[in->read]
 4856     8b/-> *(esi+4) 1/r32/ecx
 4857     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4858     89/<- *(edi+4) 0/r32/eax
 4859 $next-mu-token:end:
 4860     # . restore registers
 4861     5f/pop-to-edi
 4862     5e/pop-to-esi
 4863     59/pop-to-ecx
 4864     58/pop-to-eax
 4865     # . epilogue
 4866     89/<- %esp 5/r32/ebp
 4867     5d/pop-to-ebp
 4868     c3/return
 4869 
 4870 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 4871     # . prologue
 4872     55/push-ebp
 4873     89/<- %ebp 4/r32/esp
 4874     # if (pos-slice(arr, s) != -1) return it
 4875     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 4876     3d/compare-eax-and -1/imm32
 4877     75/jump-if-!= $pos-or-insert-slice:end/disp8
 4878 $pos-or-insert-slice:insert:
 4879     # var s2/eax: (handle array byte)
 4880     68/push 0/imm32
 4881     68/push 0/imm32
 4882     89/<- %eax 4/r32/esp
 4883     (slice-to-string Heap *(ebp+0xc) %eax)
 4884     # throw away alloc-id
 4885     (lookup *eax *(eax+4))  # => eax
 4886     (write-int *(ebp+8) %eax)
 4887     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 4888 $pos-or-insert-slice:end:
 4889     # . reclaim locals
 4890     81 0/subop/add %esp 8/imm32
 4891     # . epilogue
 4892     89/<- %esp 5/r32/ebp
 4893     5d/pop-to-ebp
 4894     c3/return
 4895 
 4896 # return the index in an array of strings matching 's', -1 if not found
 4897 # index is denominated in elements, not bytes
 4898 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 4899     # . prologue
 4900     55/push-ebp
 4901     89/<- %ebp 4/r32/esp
 4902     # . save registers
 4903     51/push-ecx
 4904     52/push-edx
 4905     53/push-ebx
 4906     56/push-esi
 4907 #?     (write-buffered Stderr "pos-slice: ")
 4908 #?     (write-slice-buffered Stderr *(ebp+0xc))
 4909 #?     (write-buffered Stderr "\n")
 4910 #?     (flush Stderr)
 4911     # esi = arr
 4912     8b/-> *(ebp+8) 6/r32/esi
 4913     # var index/ecx: int = 0
 4914     b9/copy-to-ecx 0/imm32
 4915     # var curr/edx: (addr (addr array byte)) = arr->data
 4916     8d/copy-address *(esi+0xc) 2/r32/edx
 4917     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 4918     8b/-> *esi 3/r32/ebx
 4919     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 4920     {
 4921 #?       (write-buffered Stderr "  ")
 4922 #?       (print-int32-buffered Stderr %ecx)
 4923 #?       (write-buffered Stderr "\n")
 4924 #?       (flush Stderr)
 4925       # if (curr >= max) return -1
 4926       39/compare %edx 3/r32/ebx
 4927       b8/copy-to-eax -1/imm32
 4928       73/jump-if-addr>= $pos-slice:end/disp8
 4929       # if (slice-equal?(s, *curr)) break
 4930       (slice-equal? *(ebp+0xc) *edx)  # => eax
 4931       3d/compare-eax-and 0/imm32/false
 4932       75/jump-if-!= break/disp8
 4933       # ++index
 4934       41/increment-ecx
 4935       # curr += 4
 4936       81 0/subop/add %edx 4/imm32
 4937       #
 4938       eb/jump loop/disp8
 4939     }
 4940     # return index
 4941     89/<- %eax 1/r32/ecx
 4942 $pos-slice:end:
 4943 #?     (write-buffered Stderr "=> ")
 4944 #?     (print-int32-buffered Stderr %eax)
 4945 #?     (write-buffered Stderr "\n")
 4946     # . restore registers
 4947     5e/pop-to-esi
 4948     5b/pop-to-ebx
 4949     5a/pop-to-edx
 4950     59/pop-to-ecx
 4951     # . epilogue
 4952     89/<- %esp 5/r32/ebp
 4953     5d/pop-to-ebp
 4954     c3/return
 4955 
 4956 test-parse-var-with-type:
 4957     # . prologue
 4958     55/push-ebp
 4959     89/<- %ebp 4/r32/esp
 4960     # (eax..ecx) = "x:"
 4961     b8/copy-to-eax "x:"/imm32
 4962     8b/-> *eax 1/r32/ecx
 4963     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 4964     05/add-to-eax 4/imm32
 4965     # var slice/ecx: slice = {eax, ecx}
 4966     51/push-ecx
 4967     50/push-eax
 4968     89/<- %ecx 4/r32/esp
 4969     # _test-input-stream contains "int"
 4970     (clear-stream _test-input-stream)
 4971     (write _test-input-stream "int")
 4972     # var v/edx: (handle var)
 4973     68/push 0/imm32
 4974     68/push 0/imm32
 4975     89/<- %edx 4/r32/esp
 4976     #
 4977     (parse-var-with-type %ecx _test-input-stream %edx)
 4978     # var v-addr/edx: (addr var) = lookup(v)
 4979     (lookup *edx *(edx+4))  # => eax
 4980     89/<- %edx 0/r32/eax
 4981     # check v-addr->name
 4982     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4983     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 4984     # check v-addr->type
 4985     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4986     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 4987     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 4988     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 4989     # . epilogue
 4990     89/<- %esp 5/r32/ebp
 4991     5d/pop-to-ebp
 4992     c3/return
 4993 
 4994 test-parse-var-with-type-and-register:
 4995     # . prologue
 4996     55/push-ebp
 4997     89/<- %ebp 4/r32/esp
 4998     # (eax..ecx) = "x/eax:"
 4999     b8/copy-to-eax "x/eax:"/imm32
 5000     8b/-> *eax 1/r32/ecx
 5001     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5002     05/add-to-eax 4/imm32
 5003     # var slice/ecx: slice = {eax, ecx}
 5004     51/push-ecx
 5005     50/push-eax
 5006     89/<- %ecx 4/r32/esp
 5007     # _test-input-stream contains "int"
 5008     (clear-stream _test-input-stream)
 5009     (write _test-input-stream "int")
 5010     # var v/edx: (handle var)
 5011     68/push 0/imm32
 5012     68/push 0/imm32
 5013     89/<- %edx 4/r32/esp
 5014     #
 5015     (parse-var-with-type %ecx _test-input-stream %edx)
 5016     # var v-addr/edx: (addr var) = lookup(v)
 5017     (lookup *edx *(edx+4))  # => eax
 5018     89/<- %edx 0/r32/eax
 5019     # check v-addr->name
 5020     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5021     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 5022     # check v-addr->register
 5023     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 5024     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 5025     # check v-addr->type
 5026     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5027     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 5028     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 5029     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 5030     # . epilogue
 5031     89/<- %esp 5/r32/ebp
 5032     5d/pop-to-ebp
 5033     c3/return
 5034 
 5035 test-parse-var-with-trailing-characters:
 5036     # . prologue
 5037     55/push-ebp
 5038     89/<- %ebp 4/r32/esp
 5039     # (eax..ecx) = "x:"
 5040     b8/copy-to-eax "x:"/imm32
 5041     8b/-> *eax 1/r32/ecx
 5042     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5043     05/add-to-eax 4/imm32
 5044     # var slice/ecx: slice = {eax, ecx}
 5045     51/push-ecx
 5046     50/push-eax
 5047     89/<- %ecx 4/r32/esp
 5048     # _test-input-stream contains "int,"
 5049     (clear-stream _test-input-stream)
 5050     (write _test-input-stream "int,")
 5051     # var v/edx: (handle var)
 5052     68/push 0/imm32
 5053     68/push 0/imm32
 5054     89/<- %edx 4/r32/esp
 5055     #
 5056     (parse-var-with-type %ecx _test-input-stream %edx)
 5057     # var v-addr/edx: (addr var) = lookup(v)
 5058     (lookup *edx *(edx+4))  # => eax
 5059     89/<- %edx 0/r32/eax
 5060     # check v-addr->name
 5061     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5062     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 5063     # check v-addr->register
 5064     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 5065     # check v-addr->type
 5066     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5067     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 5068     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 5069     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 5070     # . epilogue
 5071     89/<- %esp 5/r32/ebp
 5072     5d/pop-to-ebp
 5073     c3/return
 5074 
 5075 test-parse-var-with-register-and-trailing-characters:
 5076     # . prologue
 5077     55/push-ebp
 5078     89/<- %ebp 4/r32/esp
 5079     # (eax..ecx) = "x/eax:"
 5080     b8/copy-to-eax "x/eax:"/imm32
 5081     8b/-> *eax 1/r32/ecx
 5082     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5083     05/add-to-eax 4/imm32
 5084     # var slice/ecx: slice = {eax, ecx}
 5085     51/push-ecx
 5086     50/push-eax
 5087     89/<- %ecx 4/r32/esp
 5088     # _test-input-stream contains "int,"
 5089     (clear-stream _test-input-stream)
 5090     (write _test-input-stream "int,")
 5091     # var v/edx: (handle var)
 5092     68/push 0/imm32
 5093     68/push 0/imm32
 5094     89/<- %edx 4/r32/esp
 5095     #
 5096     (parse-var-with-type %ecx _test-input-stream %edx)
 5097     # var v-addr/edx: (addr var) = lookup(v)
 5098     (lookup *edx *(edx+4))  # => eax
 5099     89/<- %edx 0/r32/eax
 5100     # check v-addr->name
 5101     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5102     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 5103     # check v-addr->register
 5104     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 5105     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 5106     # check v-addr->type
 5107     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5108     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 5109     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 5110     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 5111     # . epilogue
 5112     89/<- %esp 5/r32/ebp
 5113     5d/pop-to-ebp
 5114     c3/return
 5115 
 5116 test-parse-var-with-compound-type:
 5117     # . prologue
 5118     55/push-ebp
 5119     89/<- %ebp 4/r32/esp
 5120     # (eax..ecx) = "x:"
 5121     b8/copy-to-eax "x:"/imm32
 5122     8b/-> *eax 1/r32/ecx
 5123     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5124     05/add-to-eax 4/imm32
 5125     # var slice/ecx: slice = {eax, ecx}
 5126     51/push-ecx
 5127     50/push-eax
 5128     89/<- %ecx 4/r32/esp
 5129     # _test-input-stream contains "(addr int)"
 5130     (clear-stream _test-input-stream)
 5131     (write _test-input-stream "(addr int)")
 5132     # var v/edx: (handle var)
 5133     68/push 0/imm32
 5134     68/push 0/imm32
 5135     89/<- %edx 4/r32/esp
 5136     #
 5137     (parse-var-with-type %ecx _test-input-stream %edx)
 5138     # var v-addr/edx: (addr var) = lookup(v)
 5139     (lookup *edx *(edx+4))  # => eax
 5140     89/<- %edx 0/r32/eax
 5141     # check v-addr->name
 5142     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5143     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 5144     # check v-addr->register
 5145     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 5146     # - check v-addr->type
 5147     # var type/edx: (addr tree type-id) = var->type
 5148     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5149     89/<- %edx 0/r32/eax
 5150     # type is a non-atom
 5151     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 5152     # type->left == atom(addr)
 5153     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 5154     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 5155     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 5156     # type->right->left == atom(int)
 5157     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 5158     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 5159     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 5160     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 5161     # type->right->right == null
 5162     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 5163     # . epilogue
 5164     89/<- %esp 5/r32/ebp
 5165     5d/pop-to-ebp
 5166     c3/return
 5167 
 5168 # identifier starts with a letter or '$' or '_'
 5169 # no constraints at the moment on later letters
 5170 # all we really want to do so far is exclude '{', '}' and '->'
 5171 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 5172     # . prologue
 5173     55/push-ebp
 5174     89/<- %ebp 4/r32/esp
 5175     # if (slice-empty?(in)) return false
 5176     (slice-empty? *(ebp+8))  # => eax
 5177     3d/compare-eax-and 0/imm32/false
 5178     75/jump-if-!= $is-identifier?:false/disp8
 5179     # var c/eax: byte = *in->start
 5180     8b/-> *(ebp+8) 0/r32/eax
 5181     8b/-> *eax 0/r32/eax
 5182     8a/copy-byte *eax 0/r32/AL
 5183     81 4/subop/and %eax 0xff/imm32
 5184     # if (c == '$') return true
 5185     3d/compare-eax-and 0x24/imm32/$
 5186     74/jump-if-= $is-identifier?:true/disp8
 5187     # if (c == '_') return true
 5188     3d/compare-eax-and 0x5f/imm32/_
 5189     74/jump-if-= $is-identifier?:true/disp8
 5190     # drop case
 5191     25/and-eax-with 0x5f/imm32
 5192     # if (c < 'A') return false
 5193     3d/compare-eax-and 0x41/imm32/A
 5194     7c/jump-if-< $is-identifier?:false/disp8
 5195     # if (c > 'Z') return false
 5196     3d/compare-eax-and 0x5a/imm32/Z
 5197     7f/jump-if-> $is-identifier?:false/disp8
 5198     # otherwise return true
 5199 $is-identifier?:true:
 5200     b8/copy-to-eax 1/imm32/true
 5201     eb/jump $is-identifier?:end/disp8
 5202 $is-identifier?:false:
 5203     b8/copy-to-eax 0/imm32/false
 5204 $is-identifier?:end:
 5205     # . epilogue
 5206     89/<- %esp 5/r32/ebp
 5207     5d/pop-to-ebp
 5208     c3/return
 5209 
 5210 test-is-identifier-dollar:
 5211     # . prologue
 5212     55/push-ebp
 5213     89/<- %ebp 4/r32/esp
 5214     # (eax..ecx) = "$a"
 5215     b8/copy-to-eax "$a"/imm32
 5216     8b/-> *eax 1/r32/ecx
 5217     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5218     05/add-to-eax 4/imm32
 5219     # var slice/ecx: slice = {eax, ecx}
 5220     51/push-ecx
 5221     50/push-eax
 5222     89/<- %ecx 4/r32/esp
 5223     #
 5224     (is-identifier? %ecx)
 5225     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 5226     # . epilogue
 5227     89/<- %esp 5/r32/ebp
 5228     5d/pop-to-ebp
 5229     c3/return
 5230 
 5231 test-is-identifier-underscore:
 5232     # . prologue
 5233     55/push-ebp
 5234     89/<- %ebp 4/r32/esp
 5235     # (eax..ecx) = "_a"
 5236     b8/copy-to-eax "_a"/imm32
 5237     8b/-> *eax 1/r32/ecx
 5238     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5239     05/add-to-eax 4/imm32
 5240     # var slice/ecx: slice = {eax, ecx}
 5241     51/push-ecx
 5242     50/push-eax
 5243     89/<- %ecx 4/r32/esp
 5244     #
 5245     (is-identifier? %ecx)
 5246     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 5247     # . epilogue
 5248     89/<- %esp 5/r32/ebp
 5249     5d/pop-to-ebp
 5250     c3/return
 5251 
 5252 test-is-identifier-a:
 5253     # . prologue
 5254     55/push-ebp
 5255     89/<- %ebp 4/r32/esp
 5256     # (eax..ecx) = "a$"
 5257     b8/copy-to-eax "a$"/imm32
 5258     8b/-> *eax 1/r32/ecx
 5259     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5260     05/add-to-eax 4/imm32
 5261     # var slice/ecx: slice = {eax, ecx}
 5262     51/push-ecx
 5263     50/push-eax
 5264     89/<- %ecx 4/r32/esp
 5265     #
 5266     (is-identifier? %ecx)
 5267     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 5268     # . epilogue
 5269     89/<- %esp 5/r32/ebp
 5270     5d/pop-to-ebp
 5271     c3/return
 5272 
 5273 test-is-identifier-z:
 5274     # . prologue
 5275     55/push-ebp
 5276     89/<- %ebp 4/r32/esp
 5277     # (eax..ecx) = "z$"
 5278     b8/copy-to-eax "z$"/imm32
 5279     8b/-> *eax 1/r32/ecx
 5280     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5281     05/add-to-eax 4/imm32
 5282     # var slice/ecx: slice = {eax, ecx}
 5283     51/push-ecx
 5284     50/push-eax
 5285     89/<- %ecx 4/r32/esp
 5286     #
 5287     (is-identifier? %ecx)
 5288     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 5289     # . epilogue
 5290     89/<- %esp 5/r32/ebp
 5291     5d/pop-to-ebp
 5292     c3/return
 5293 
 5294 test-is-identifier-A:
 5295     # . prologue
 5296     55/push-ebp
 5297     89/<- %ebp 4/r32/esp
 5298     # (eax..ecx) = "A$"
 5299     b8/copy-to-eax "A$"/imm32
 5300     8b/-> *eax 1/r32/ecx
 5301     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5302     05/add-to-eax 4/imm32
 5303     # var slice/ecx: slice = {eax, ecx}
 5304     51/push-ecx
 5305     50/push-eax
 5306     89/<- %ecx 4/r32/esp
 5307     #
 5308     (is-identifier? %ecx)
 5309     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 5310     # . epilogue
 5311     89/<- %esp 5/r32/ebp
 5312     5d/pop-to-ebp
 5313     c3/return
 5314 
 5315 test-is-identifier-Z:
 5316     # . prologue
 5317     55/push-ebp
 5318     89/<- %ebp 4/r32/esp
 5319     # (eax..ecx) = "Z$"
 5320     b8/copy-to-eax "Z$"/imm32
 5321     8b/-> *eax 1/r32/ecx
 5322     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5323     05/add-to-eax 4/imm32
 5324     # var slice/ecx: slice = {eax, ecx}
 5325     51/push-ecx
 5326     50/push-eax
 5327     89/<- %ecx 4/r32/esp
 5328     #
 5329     (is-identifier? %ecx)
 5330     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 5331     # . epilogue
 5332     89/<- %esp 5/r32/ebp
 5333     5d/pop-to-ebp
 5334     c3/return
 5335 
 5336 test-is-identifier-at:
 5337     # character before 'A' is invalid
 5338     # . prologue
 5339     55/push-ebp
 5340     89/<- %ebp 4/r32/esp
 5341     # (eax..ecx) = "@a"
 5342     b8/copy-to-eax "@a"/imm32
 5343     8b/-> *eax 1/r32/ecx
 5344     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5345     05/add-to-eax 4/imm32
 5346     # var slice/ecx: slice = {eax, ecx}
 5347     51/push-ecx
 5348     50/push-eax
 5349     89/<- %ecx 4/r32/esp
 5350     #
 5351     (is-identifier? %ecx)
 5352     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5353     # . epilogue
 5354     89/<- %esp 5/r32/ebp
 5355     5d/pop-to-ebp
 5356     c3/return
 5357 
 5358 test-is-identifier-square-bracket:
 5359     # character after 'Z' is invalid
 5360     # . prologue
 5361     55/push-ebp
 5362     89/<- %ebp 4/r32/esp
 5363     # (eax..ecx) = "[a"
 5364     b8/copy-to-eax "[a"/imm32
 5365     8b/-> *eax 1/r32/ecx
 5366     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5367     05/add-to-eax 4/imm32
 5368     # var slice/ecx: slice = {eax, ecx}
 5369     51/push-ecx
 5370     50/push-eax
 5371     89/<- %ecx 4/r32/esp
 5372     #
 5373     (is-identifier? %ecx)
 5374     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5375     # . epilogue
 5376     89/<- %esp 5/r32/ebp
 5377     5d/pop-to-ebp
 5378     c3/return
 5379 
 5380 test-is-identifier-backtick:
 5381     # character before 'a' is invalid
 5382     # . prologue
 5383     55/push-ebp
 5384     89/<- %ebp 4/r32/esp
 5385     # (eax..ecx) = "`a"
 5386     b8/copy-to-eax "`a"/imm32
 5387     8b/-> *eax 1/r32/ecx
 5388     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5389     05/add-to-eax 4/imm32
 5390     # var slice/ecx: slice = {eax, ecx}
 5391     51/push-ecx
 5392     50/push-eax
 5393     89/<- %ecx 4/r32/esp
 5394     #
 5395     (is-identifier? %ecx)
 5396     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 5397     # . epilogue
 5398     89/<- %esp 5/r32/ebp
 5399     5d/pop-to-ebp
 5400     c3/return
 5401 
 5402 test-is-identifier-curly-brace-open:
 5403     # character after 'z' is invalid; also used for blocks
 5404     # . prologue
 5405     55/push-ebp
 5406     89/<- %ebp 4/r32/esp
 5407     # (eax..ecx) = "{a"
 5408     b8/copy-to-eax "{a"/imm32
 5409     8b/-> *eax 1/r32/ecx
 5410     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5411     05/add-to-eax 4/imm32
 5412     # var slice/ecx: slice = {eax, ecx}
 5413     51/push-ecx
 5414     50/push-eax
 5415     89/<- %ecx 4/r32/esp
 5416     #
 5417     (is-identifier? %ecx)
 5418     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 5419     # . epilogue
 5420     89/<- %esp 5/r32/ebp
 5421     5d/pop-to-ebp
 5422     c3/return
 5423 
 5424 test-is-identifier-curly-brace-close:
 5425     # . prologue
 5426     55/push-ebp
 5427     89/<- %ebp 4/r32/esp
 5428     # (eax..ecx) = "}a"
 5429     b8/copy-to-eax "}a"/imm32
 5430     8b/-> *eax 1/r32/ecx
 5431     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5432     05/add-to-eax 4/imm32
 5433     # var slice/ecx: slice = {eax, ecx}
 5434     51/push-ecx
 5435     50/push-eax
 5436     89/<- %ecx 4/r32/esp
 5437     #
 5438     (is-identifier? %ecx)
 5439     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 5440     # . epilogue
 5441     89/<- %esp 5/r32/ebp
 5442     5d/pop-to-ebp
 5443     c3/return
 5444 
 5445 test-is-identifier-hyphen:
 5446     # disallow leading '-' since '->' has special meaning
 5447     # . prologue
 5448     55/push-ebp
 5449     89/<- %ebp 4/r32/esp
 5450     # (eax..ecx) = "-a"
 5451     b8/copy-to-eax "-a"/imm32
 5452     8b/-> *eax 1/r32/ecx
 5453     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5454     05/add-to-eax 4/imm32
 5455     # var slice/ecx: slice = {eax, ecx}
 5456     51/push-ecx
 5457     50/push-eax
 5458     89/<- %ecx 4/r32/esp
 5459     #
 5460     (is-identifier? %ecx)
 5461     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 5462     # . epilogue
 5463     89/<- %esp 5/r32/ebp
 5464     5d/pop-to-ebp
 5465     c3/return
 5466 
 5467 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var)
 5468     # . prologue
 5469     55/push-ebp
 5470     89/<- %ebp 4/r32/esp
 5471     # . save registers
 5472     50/push-eax
 5473     56/push-esi
 5474     57/push-edi
 5475     # esi = in
 5476     8b/-> *(ebp+8) 6/r32/esi
 5477     # edi = out
 5478     8b/-> *(ebp+0xc) 7/r32/edi
 5479     # parse-mu-block(in, vars, out, out->body)
 5480     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 5481     (parse-mu-block %esi *(ebp+0x10) %edi %eax)
 5482 $populate-mu-function-body:end:
 5483     # . restore registers
 5484     5f/pop-to-edi
 5485     5e/pop-to-esi
 5486     58/pop-to-eax
 5487     # . epilogue
 5488     89/<- %esp 5/r32/ebp
 5489     5d/pop-to-ebp
 5490     c3/return
 5491 
 5492 # parses a block, assuming that the leading '{' has already been read by the caller
 5493 parse-mu-block:  # in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle block)
 5494     # pseudocode:
 5495     #   var line: (stream byte 512)
 5496     #   var word-slice: slice
 5497     #   allocate(Heap, Stmt-size, out)
 5498     #   var out-addr: (addr block) = lookup(*out)
 5499     #   out-addr->tag = 0/block
 5500     #   out-addr->var = some unique name
 5501     #   push(vars, {out-addr->var, false})
 5502     #   while true                                  # line loop
 5503     #     clear-stream(line)
 5504     #     read-line-buffered(in, line)
 5505     #     if (line->write == 0) break               # end of file
 5506     #     word-slice = next-mu-token(line)
 5507     #     if slice-empty?(word-slice)               # end of line
 5508     #       continue
 5509     #     else if slice-starts-with?(word-slice, "#")
 5510     #       continue
 5511     #     else if slice-equal?(word-slice, "{")
 5512     #       assert(no-tokens-in(line))
 5513     #       block = parse-mu-block(in, vars, fn)
 5514     #       append-to-block(out-addr, block)
 5515     #     else if slice-equal?(word-slice, "}")
 5516     #       break
 5517     #     else if slice-ends-with?(word-slice, ":")
 5518     #       # TODO: error-check the rest of 'line'
 5519     #       --word-slice->end to skip ':'
 5520     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 5521     #       append-to-block(out-addr, named-block)
 5522     #     else if slice-equal?(word-slice, "var")
 5523     #       var-def = parse-mu-var-def(line, vars)
 5524     #       append-to-block(out-addr, var-def)
 5525     #     else
 5526     #       stmt = parse-mu-stmt(line, vars, fn)
 5527     #       append-to-block(out-addr, stmt)
 5528     #   pop(vars)
 5529     #
 5530     # . prologue
 5531     55/push-ebp
 5532     89/<- %ebp 4/r32/esp
 5533     # . save registers
 5534     50/push-eax
 5535     51/push-ecx
 5536     52/push-edx
 5537     53/push-ebx
 5538     57/push-edi
 5539     # var line/ecx: (stream byte 512)
 5540     81 5/subop/subtract %esp 0x200/imm32
 5541     68/push 0x200/imm32/size
 5542     68/push 0/imm32/read
 5543     68/push 0/imm32/write
 5544     89/<- %ecx 4/r32/esp
 5545     # var word-slice/edx: slice
 5546     68/push 0/imm32/end
 5547     68/push 0/imm32/start
 5548     89/<- %edx 4/r32/esp
 5549     # allocate into out
 5550     (allocate Heap *Stmt-size *(ebp+0x14))
 5551     # var out-addr/edi: (addr block) = lookup(*out)
 5552     8b/-> *(ebp+0x14) 7/r32/edi
 5553     (lookup *edi *(edi+4))  # => eax
 5554     89/<- %edi 0/r32/eax
 5555     # out-addr->tag is 0 (block) by default
 5556     # set out-addr->var
 5557     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 5558     (new-block-name *(ebp+0x10) %eax)
 5559     # push(vars, out-addr->var)
 5560     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 5561     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 5562     (push *(ebp+0xc) 0)  # false
 5563     {
 5564 $parse-mu-block:line-loop:
 5565       # line = read-line-buffered(in)
 5566       (clear-stream %ecx)
 5567       (read-line-buffered *(ebp+8) %ecx)
 5568 #?       (write-buffered Stderr "line: ")
 5569 #?       (write-stream-data Stderr %ecx)
 5570 #?       (write-buffered Stderr Newline)
 5571 #?       (flush Stderr)
 5572       # if (line->write == 0) break
 5573       81 7/subop/compare *ecx 0/imm32
 5574       0f 84/jump-if-= break/disp32
 5575       # word-slice = next-mu-token(line)
 5576       (next-mu-token %ecx %edx)
 5577 #?       (write-buffered Stderr "word: ")
 5578 #?       (write-slice-buffered Stderr %edx)
 5579 #?       (write-buffered Stderr Newline)
 5580 #?       (flush Stderr)
 5581       # if slice-empty?(word-slice) continue
 5582       (slice-empty? %edx)
 5583       3d/compare-eax-and 0/imm32/false
 5584       0f 85/jump-if-!= loop/disp32
 5585       # if (slice-starts-with?(word-slice, '#') continue
 5586       # . eax = *word-slice->start
 5587       8b/-> *edx 0/r32/eax
 5588       8a/copy-byte *eax 0/r32/AL
 5589       81 4/subop/and %eax 0xff/imm32
 5590       # . if (eax == '#') continue
 5591       3d/compare-eax-and 0x23/imm32/hash
 5592       0f 84/jump-if-= loop/disp32
 5593       # if slice-equal?(word-slice, "{")
 5594       {
 5595 $parse-mu-block:check-for-block:
 5596         (slice-equal? %edx "{")
 5597         3d/compare-eax-and 0/imm32/false
 5598         74/jump-if-= break/disp8
 5599         (check-no-tokens-left %ecx)
 5600         # parse new block and append
 5601         # . var tmp/eax: (handle block)
 5602         68/push 0/imm32
 5603         68/push 0/imm32
 5604         89/<- %eax 4/r32/esp
 5605         # .
 5606         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax)
 5607         (append-to-block Heap %edi  *eax *(eax+4))
 5608         # . reclaim tmp
 5609         81 0/subop/add %esp 8/imm32
 5610         # .
 5611         e9/jump $parse-mu-block:line-loop/disp32
 5612       }
 5613       # if slice-equal?(word-slice, "}") break
 5614 $parse-mu-block:check-for-end:
 5615       (slice-equal? %edx "}")
 5616       3d/compare-eax-and 0/imm32/false
 5617       0f 85/jump-if-!= break/disp32
 5618       # if slice-ends-with?(word-slice, ":") parse named block and append
 5619       {
 5620 $parse-mu-block:check-for-named-block:
 5621         # . eax = *(word-slice->end-1)
 5622         8b/-> *(edx+4) 0/r32/eax
 5623         48/decrement-eax
 5624         8a/copy-byte *eax 0/r32/AL
 5625         81 4/subop/and %eax 0xff/imm32
 5626         # . if (eax != ':') break
 5627         3d/compare-eax-and 0x3a/imm32/colon
 5628         0f 85/jump-if-!= break/disp32
 5629         # TODO: error-check the rest of 'line'
 5630         #
 5631         # skip ':'
 5632         ff 1/subop/decrement *(edx+4)  # Slice-end
 5633         # var tmp/eax: (handle block)
 5634         68/push 0/imm32
 5635         68/push 0/imm32
 5636         89/<- %eax 4/r32/esp
 5637         #
 5638         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax)
 5639         (append-to-block Heap %edi  *eax *(eax+4))
 5640         # reclaim tmp
 5641         81 0/subop/add %esp 8/imm32
 5642         #
 5643         e9/jump $parse-mu-block:line-loop/disp32
 5644       }
 5645       # if slice-equal?(word-slice, "var")
 5646       {
 5647 $parse-mu-block:check-for-var:
 5648         (slice-equal? %edx "var")
 5649         3d/compare-eax-and 0/imm32/false
 5650         74/jump-if-= break/disp8
 5651         # var tmp/eax: (handle block)
 5652         68/push 0/imm32
 5653         68/push 0/imm32
 5654         89/<- %eax 4/r32/esp
 5655         #
 5656         (parse-mu-var-def %ecx *(ebp+0xc) %eax)
 5657         (append-to-block Heap %edi  *eax *(eax+4))
 5658         # reclaim tmp
 5659         81 0/subop/add %esp 8/imm32
 5660         #
 5661         e9/jump $parse-mu-block:line-loop/disp32
 5662       }
 5663 $parse-mu-block:regular-stmt:
 5664       # otherwise
 5665       # var tmp/eax: (handle block)
 5666       68/push 0/imm32
 5667       68/push 0/imm32
 5668       89/<- %eax 4/r32/esp
 5669       #
 5670       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax)
 5671       (append-to-block Heap %edi  *eax *(eax+4))
 5672       # reclaim tmp
 5673       81 0/subop/add %esp 8/imm32
 5674       #
 5675       e9/jump loop/disp32
 5676     } # end line loop
 5677     # pop(vars)
 5678     (pop *(ebp+0xc))  # => eax
 5679     (pop *(ebp+0xc))  # => eax
 5680     (pop *(ebp+0xc))  # => eax
 5681 $parse-mu-block:end:
 5682     # . reclaim locals
 5683     81 0/subop/add %esp 0x214/imm32
 5684     # . restore registers
 5685     5f/pop-to-edi
 5686     5b/pop-to-ebx
 5687     5a/pop-to-edx
 5688     59/pop-to-ecx
 5689     58/pop-to-eax
 5690     # . epilogue
 5691     89/<- %esp 5/r32/ebp
 5692     5d/pop-to-ebp
 5693     c3/return
 5694 
 5695 $parse-mu-block:abort:
 5696     # error("'{' or '}' should be on its own line, but got '")
 5697     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 5698     (rewind-stream %ecx)
 5699     (write-stream 2 %ecx)
 5700     (write-buffered Stderr "'\n")
 5701     (flush Stderr)
 5702     # . syscall(exit, 1)
 5703     bb/copy-to-ebx  1/imm32
 5704     b8/copy-to-eax  1/imm32/exit
 5705     cd/syscall  0x80/imm8
 5706     # never gets here
 5707 
 5708 new-block-name:  # fn: (addr function), out: (addr handle var)
 5709     # . prologue
 5710     55/push-ebp
 5711     89/<- %ebp 4/r32/esp
 5712     # . save registers
 5713     50/push-eax
 5714     51/push-ecx
 5715     52/push-edx
 5716     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 5717     8b/-> *(ebp+8) 0/r32/eax
 5718     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5719     8b/-> *eax 0/r32/eax  # String-size
 5720     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 5721     89/<- %ecx 0/r32/eax
 5722     # var name/edx: (stream byte n)
 5723     29/subtract-from %esp 1/r32/ecx
 5724     ff 6/subop/push %ecx
 5725     68/push 0/imm32/read
 5726     68/push 0/imm32/write
 5727     89/<- %edx 4/r32/esp
 5728     (clear-stream %edx)
 5729     # eax = fn->name
 5730     8b/-> *(ebp+8) 0/r32/eax
 5731     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5732     # construct result using Next-block-index (and increment it)
 5733     (write %edx "$")
 5734     (write %edx %eax)
 5735     (write %edx ":")
 5736     (print-int32 %edx *Next-block-index)
 5737     ff 0/subop/increment *Next-block-index
 5738     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 5739     # . eax = name->write
 5740     8b/-> *edx 0/r32/eax
 5741     # . edx = name->data
 5742     8d/copy-address *(edx+0xc) 2/r32/edx
 5743     # . eax = name->write + name->data
 5744     01/add-to %eax 2/r32/edx
 5745     # . push {edx, eax}
 5746     ff 6/subop/push %eax
 5747     ff 6/subop/push %edx
 5748     89/<- %eax 4/r32/esp
 5749     # out = new literal(s)
 5750     (new-literal Heap %eax *(ebp+0xc))
 5751 #?     8b/-> *(ebp+0xc) 0/r32/eax
 5752 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 5753 #?     (print-int32-buffered Stderr *(eax+8))
 5754 #?     (write-buffered Stderr " for var ")
 5755 #?     (print-int32-buffered Stderr %eax)
 5756 #?     (write-buffered Stderr Newline)
 5757 #?     (flush Stderr)
 5758 $new-block-name:end:
 5759     # . reclaim locals
 5760     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 5761     81 0/subop/add %ecx 8/imm32  # slice
 5762     01/add-to %esp 1/r32/ecx
 5763     # . restore registers
 5764     5a/pop-to-edx
 5765     59/pop-to-ecx
 5766     58/pop-to-eax
 5767     # . epilogue
 5768     89/<- %esp 5/r32/ebp
 5769     5d/pop-to-ebp
 5770     c3/return
 5771 
 5772 == data
 5773 
 5774 # Global state added to each var record when parsing a function
 5775 Next-block-index:  # (addr int)
 5776     1/imm32
 5777 
 5778 == code
 5779 
 5780 check-no-tokens-left:  # line: (addr stream byte)
 5781     # . prologue
 5782     55/push-ebp
 5783     89/<- %ebp 4/r32/esp
 5784     # . save registers
 5785     50/push-eax
 5786     51/push-ecx
 5787     # var s/ecx: slice
 5788     68/push 0/imm32/end
 5789     68/push 0/imm32/start
 5790     89/<- %ecx 4/r32/esp
 5791     #
 5792     (next-mu-token *(ebp+8) %ecx)
 5793     # if slice-empty?(s) return
 5794     (slice-empty? %ecx)
 5795     3d/compare-eax-and 0/imm32/false
 5796     75/jump-if-!= $check-no-tokens-left:end/disp8
 5797     # if (slice-starts-with?(s, '#') return
 5798     # . eax = *s->start
 5799     8b/-> *edx 0/r32/eax
 5800     8a/copy-byte *eax 0/r32/AL
 5801     81 4/subop/and %eax 0xff/imm32
 5802     # . if (eax == '#') continue
 5803     3d/compare-eax-and 0x23/imm32/hash
 5804     74/jump-if-= $check-no-tokens-left:end/disp8
 5805     # abort
 5806     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 5807     (rewind-stream %ecx)
 5808     (write-stream 2 %ecx)
 5809     (write-buffered Stderr "'\n")
 5810     (flush Stderr)
 5811     # . syscall(exit, 1)
 5812     bb/copy-to-ebx  1/imm32
 5813     b8/copy-to-eax  1/imm32/exit
 5814     cd/syscall  0x80/imm8
 5815     # never gets here
 5816 $check-no-tokens-left:end:
 5817     # . reclaim locals
 5818     81 0/subop/add %esp 8/imm32
 5819     # . restore registers
 5820     59/pop-to-ecx
 5821     58/pop-to-eax
 5822     # . epilogue
 5823     89/<- %esp 5/r32/ebp
 5824     5d/pop-to-ebp
 5825     c3/return
 5826 
 5827 parse-mu-named-block:  # name: (addr slice), in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt)
 5828     # pseudocode:
 5829     #   var v: (handle var)
 5830     #   new-literal(name, v)
 5831     #   push(vars, {v, false})
 5832     #   parse-mu-block(in, vars, fn, out)
 5833     #   pop(vars)
 5834     #   out->tag = block
 5835     #   out->var = v
 5836     #
 5837     # . prologue
 5838     55/push-ebp
 5839     89/<- %ebp 4/r32/esp
 5840     # . save registers
 5841     50/push-eax
 5842     51/push-ecx
 5843     57/push-edi
 5844     # var v/ecx: (handle var)
 5845     68/push 0/imm32
 5846     68/push 0/imm32
 5847     89/<- %ecx 4/r32/esp
 5848     #
 5849     (new-literal Heap *(ebp+8) %ecx)
 5850     # push(vars, v)
 5851     (push *(ebp+0x10) *ecx)
 5852     (push *(ebp+0x10) *(ecx+4))
 5853     (push *(ebp+0x10) 0)  # false
 5854     #
 5855     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 5856     # pop v off vars
 5857     (pop *(ebp+0x10))  # => eax
 5858     (pop *(ebp+0x10))  # => eax
 5859     (pop *(ebp+0x10))  # => eax
 5860     # var out-addr/edi: (addr stmt) = lookup(*out)
 5861     8b/-> *(ebp+0x18) 7/r32/edi
 5862     (lookup *edi *(edi+4))  # => eax
 5863     89/<- %edi 0/r32/eax
 5864     # out-addr->tag = named-block
 5865     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 5866     # out-addr->var = v
 5867     8b/-> *ecx 0/r32/eax
 5868     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 5869     8b/-> *(ecx+4) 0/r32/eax
 5870     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 5871 $parse-mu-named-block:end:
 5872     # . reclaim locals
 5873     81 0/subop/add %esp 8/imm32
 5874     # . restore registers
 5875     5f/pop-to-edi
 5876     59/pop-to-ecx
 5877     58/pop-to-eax
 5878     # . epilogue
 5879     89/<- %esp 5/r32/ebp
 5880     5d/pop-to-ebp
 5881     c3/return
 5882 
 5883 parse-mu-var-def:  # line: (addr stream byte), vars: (addr stack live-var), out: (addr handle stmt)
 5884     # . prologue
 5885     55/push-ebp
 5886     89/<- %ebp 4/r32/esp
 5887     # . save registers
 5888     50/push-eax
 5889     51/push-ecx
 5890     52/push-edx
 5891     57/push-edi
 5892     # edi = out
 5893     8b/-> *(ebp+0x10) 7/r32/edi
 5894     # var word-slice/ecx: slice
 5895     68/push 0/imm32/end
 5896     68/push 0/imm32/start
 5897     89/<- %ecx 4/r32/esp
 5898     # var v/edx: (handle var)
 5899     68/push 0/imm32
 5900     68/push 0/imm32
 5901     89/<- %edx 4/r32/esp
 5902     # v = parse-var-with-type(next-mu-token(line))
 5903     (next-mu-token *(ebp+8) %ecx)
 5904     (parse-var-with-type %ecx *(ebp+8) %edx)
 5905     #
 5906     (push *(ebp+0xc) *edx)
 5907     (push *(ebp+0xc) *(edx+4))
 5908     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 5909     # either v has no register and there's no more to this line
 5910     (lookup *edx *(edx+4))  # => eax
 5911     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 5912     3d/compare-eax-and 0/imm32
 5913     {
 5914       75/jump-if-!= break/disp8
 5915       # TODO: ensure that there's nothing else on this line
 5916       (new-var-def Heap  *edx *(edx+4)  %edi)
 5917       eb/jump $parse-mu-var-def:end/disp8
 5918     }
 5919     # or v has a register and there's more to this line
 5920     {
 5921       74/jump-if-= break/disp8
 5922       # ensure that the next word is '<-'
 5923       (next-mu-token *(ebp+8) %ecx)
 5924       (slice-equal? %ecx "<-")  # => eax
 5925       3d/compare-eax-and 0/imm32/false
 5926       74/jump-if-= $parse-mu-var-def:abort/disp8
 5927       #
 5928       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 5929       (lookup *edi *(edi+4))  # => eax
 5930       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc))
 5931     }
 5932 $parse-mu-var-def:end:
 5933     # . reclaim locals
 5934     81 0/subop/add %esp 0x10/imm32
 5935     # . restore registers
 5936     5f/pop-to-edi
 5937     5a/pop-to-edx
 5938     59/pop-to-ecx
 5939     58/pop-to-eax
 5940     # . epilogue
 5941     89/<- %esp 5/r32/ebp
 5942     5d/pop-to-ebp
 5943     c3/return
 5944 
 5945 $parse-mu-var-def:abort:
 5946     (rewind-stream *(ebp+8))
 5947     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 5948     (write-buffered Stderr "register variable requires a valid instruction to initialize but got '")
 5949     (flush Stderr)
 5950     (write-stream 2 *(ebp+8))
 5951     (write-buffered Stderr "'\n")
 5952     (flush Stderr)
 5953     # . syscall(exit, 1)
 5954     bb/copy-to-ebx  1/imm32
 5955     b8/copy-to-eax  1/imm32/exit
 5956     cd/syscall  0x80/imm8
 5957     # never gets here
 5958 
 5959 test-parse-mu-var-def:
 5960     # 'var n: int'
 5961     # . prologue
 5962     55/push-ebp
 5963     89/<- %ebp 4/r32/esp
 5964     # setup
 5965     (clear-stream _test-input-stream)
 5966     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 5967     # var out/esi: (handle stmt)
 5968     68/push 0/imm32
 5969     68/push 0/imm32
 5970     89/<- %esi 4/r32/esp
 5971     # var vars/ecx: (stack (addr var) 16)
 5972     81 5/subop/subtract %esp 0xc0/imm32
 5973     68/push 0xc0/imm32/size
 5974     68/push 0/imm32/top
 5975     89/<- %ecx 4/r32/esp
 5976     (clear-stack %ecx)
 5977     # convert
 5978     (parse-mu-var-def _test-input-stream %ecx %esi)
 5979     # var out-addr/esi: (addr stmt)
 5980     (lookup *esi *(esi+4))  # => eax
 5981     89/<- %esi 0/r32/eax
 5982     #
 5983     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 5984     # var v/ecx: (addr var) = lookup(out->var)
 5985     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 5986     89/<- %ecx 0/r32/eax
 5987     # v->name
 5988     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 5989     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 5990     # v->register
 5991     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 5992     # v->type == int
 5993     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 5994     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 5995     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 5996     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 5997     # . epilogue
 5998     89/<- %esp 5/r32/ebp
 5999     5d/pop-to-ebp
 6000     c3/return
 6001 
 6002 test-parse-mu-reg-var-def:
 6003     # 'var n/eax: int <- copy 0'
 6004     # . prologue
 6005     55/push-ebp
 6006     89/<- %ebp 4/r32/esp
 6007     # setup
 6008     (clear-stream _test-input-stream)
 6009     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 6010     # var out/esi: (handle stmt)
 6011     68/push 0/imm32
 6012     68/push 0/imm32
 6013     89/<- %esi 4/r32/esp
 6014     # var vars/ecx: (stack (addr var) 16)
 6015     81 5/subop/subtract %esp 0xc0/imm32
 6016     68/push 0xc0/imm32/size
 6017     68/push 0/imm32/top
 6018     89/<- %ecx 4/r32/esp
 6019     (clear-stack %ecx)
 6020     # convert
 6021     (parse-mu-var-def _test-input-stream %ecx %esi)
 6022     # var out-addr/esi: (addr stmt)
 6023     (lookup *esi *(esi+4))  # => eax
 6024     89/<- %esi 0/r32/eax
 6025     #
 6026     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 6027     # var v/ecx: (addr var) = lookup(out->outputs->value)
 6028     # . eax: (addr stmt-var) = lookup(out->outputs)
 6029     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 6030     # .
 6031     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 6032     # . eax: (addr var) = lookup(eax->value)
 6033     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6034     # . ecx = eax
 6035     89/<- %ecx 0/r32/eax
 6036     # v->name
 6037     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6038     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 6039     # v->register
 6040     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 6041     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 6042     # v->type == int
 6043     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6044     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 6045     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 6046     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 6047     # . epilogue
 6048     89/<- %esp 5/r32/ebp
 6049     5d/pop-to-ebp
 6050     c3/return
 6051 
 6052 parse-mu-stmt:  # line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt)
 6053     # pseudocode:
 6054     #   var name: slice
 6055     #   allocate(Heap, Stmt-size, out)
 6056     #   var out-addr: (addr stmt) = lookup(*out)
 6057     #   out-addr->tag = stmt
 6058     #   if stmt-has-outputs?(line)
 6059     #     while true
 6060     #       name = next-mu-token(line)
 6061     #       if (name == '<-') break
 6062     #       assert(is-identifier?(name))
 6063     #       var v: (handle var) = lookup-or-define-var(name, vars, fn)  # regular stmts may define vars in fn outputs
 6064     #       out-addr->outputs = append(v, out-addr->outputs)
 6065     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 6066     #
 6067     # . prologue
 6068     55/push-ebp
 6069     89/<- %ebp 4/r32/esp
 6070     # . save registers
 6071     50/push-eax
 6072     51/push-ecx
 6073     52/push-edx
 6074     53/push-ebx
 6075     57/push-edi
 6076     # var name/ecx: slice
 6077     68/push 0/imm32/end
 6078     68/push 0/imm32/start
 6079     89/<- %ecx 4/r32/esp
 6080     # var is-deref?/edx: boolean = false
 6081     ba/copy-to-edx 0/imm32/false
 6082     # var v: (handle var)
 6083     68/push 0/imm32
 6084     68/push 0/imm32
 6085     89/<- %ebx 4/r32/esp
 6086     #
 6087     (allocate Heap *Stmt-size *(ebp+0x14))
 6088     # var out-addr/edi: (addr stmt) = lookup(*out)
 6089     8b/-> *(ebp+0x14) 7/r32/edi
 6090     (lookup *edi *(edi+4))  # => eax
 6091     89/<- %edi 0/r32/eax
 6092     # out-addr->tag = 1/stmt
 6093     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 6094     {
 6095       (stmt-has-outputs? *(ebp+8))
 6096       3d/compare-eax-and 0/imm32/false
 6097       0f 84/jump-if-= break/disp32
 6098       {
 6099 $parse-mu-stmt:read-outputs:
 6100         # name = next-mu-token(line)
 6101         (next-mu-token *(ebp+8) %ecx)
 6102         # if slice-empty?(word-slice) break
 6103         (slice-empty? %ecx)  # => eax
 6104         3d/compare-eax-and 0/imm32/false
 6105         0f 85/jump-if-!= break/disp32
 6106         # if (name == "<-") break
 6107         (slice-equal? %ecx "<-")  # => eax
 6108         3d/compare-eax-and 0/imm32/false
 6109         0f 85/jump-if-!= break/disp32
 6110         # is-deref? = false
 6111         ba/copy-to-edx 0/imm32/false
 6112         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 6113         8b/-> *ecx 0/r32/eax  # Slice-start
 6114         8a/copy-byte *eax 0/r32/AL
 6115         81 4/subop/and %eax 0xff/imm32
 6116         3d/compare-eax-and 0x2a/imm32/asterisk
 6117         {
 6118           75/jump-if-!= break/disp8
 6119           ff 0/subop/increment *ecx
 6120           ba/copy-to-edx 1/imm32/true
 6121         }
 6122         # assert(is-identifier?(name))
 6123         (is-identifier? %ecx)  # => eax
 6124         3d/compare-eax-and 0/imm32/false
 6125         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 6126         #
 6127         (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx)
 6128         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 6129         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 6130         #
 6131         e9/jump loop/disp32
 6132       }
 6133     }
 6134     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc))
 6135 $parse-mu-stmt:end:
 6136     # . reclaim locals
 6137     81 0/subop/add %esp 0x10/imm32
 6138     # . restore registers
 6139     5f/pop-to-edi
 6140     5b/pop-to-ebx
 6141     5a/pop-to-edx
 6142     59/pop-to-ecx
 6143     58/pop-to-eax
 6144     # . epilogue
 6145     89/<- %esp 5/r32/ebp
 6146     5d/pop-to-ebp
 6147     c3/return
 6148 
 6149 $parse-mu-stmt:abort:
 6150     # error("invalid identifier '" name "'\n")
 6151     (write-buffered Stderr "invalid identifier '")
 6152     (write-slice-buffered Stderr %ecx)
 6153     (write-buffered Stderr "'\n")
 6154     (flush Stderr)
 6155     # . syscall(exit, 1)
 6156     bb/copy-to-ebx  1/imm32
 6157     b8/copy-to-eax  1/imm32/exit
 6158     cd/syscall  0x80/imm8
 6159     # never gets here
 6160 
 6161 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var)
 6162     # pseudocode:
 6163     #   stmt->name = slice-to-string(next-mu-token(line))
 6164     #   while true
 6165     #     name = next-mu-token(line)
 6166     #     v = lookup-var-or-literal(name)
 6167     #     stmt->inouts = append(v, stmt->inouts)
 6168     #
 6169     # . prologue
 6170     55/push-ebp
 6171     89/<- %ebp 4/r32/esp
 6172     # . save registers
 6173     50/push-eax
 6174     51/push-ecx
 6175     52/push-edx
 6176     53/push-ebx
 6177     56/push-esi
 6178     57/push-edi
 6179     # edi = stmt
 6180     8b/-> *(ebp+8) 7/r32/edi
 6181     # var name/ecx: slice
 6182     68/push 0/imm32/end
 6183     68/push 0/imm32/start
 6184     89/<- %ecx 4/r32/esp
 6185     # var is-deref?/edx: boolean = false
 6186     ba/copy-to-edx 0/imm32/false
 6187     # var v/esi: (handle var)
 6188     68/push 0/imm32
 6189     68/push 0/imm32
 6190     89/<- %esi 4/r32/esp
 6191 $add-operation-and-inputs-to-stmt:read-operation:
 6192     (next-mu-token *(ebp+0xc) %ecx)
 6193     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 6194     (slice-to-string Heap %ecx %eax)
 6195     # var is-get?/ebx: boolean = (name == "get")
 6196     (slice-equal? %ecx "get")  # => eax
 6197     89/<- %ebx 0/r32/eax
 6198     {
 6199 $add-operation-and-inputs-to-stmt:read-inouts:
 6200       # name = next-mu-token(line)
 6201       (next-mu-token *(ebp+0xc) %ecx)
 6202       # if slice-empty?(word-slice) break
 6203       (slice-empty? %ecx)  # => eax
 6204       3d/compare-eax-and 0/imm32/false
 6205       0f 85/jump-if-!= break/disp32
 6206       # if (name == "<-") abort
 6207       (slice-equal? %ecx "<-")
 6208       3d/compare-eax-and 0/imm32/false
 6209       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 6210       # if (is-get? && second operand) lookup or create offset
 6211       {
 6212         81 7/subop/compare %ebx 0/imm32/false
 6213         74/jump-if-= break/disp8
 6214         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6215         3d/compare-eax-and 0/imm32
 6216         74/jump-if-= break/disp8
 6217         (lookup-or-create-constant %eax %ecx %esi)
 6218 #?         (lookup *esi *(esi+4))
 6219 #?         (write-buffered Stderr "creating new output var ")
 6220 #?         (print-int32-buffered Stderr %eax)
 6221 #?         (write-buffered Stderr " for field called ")
 6222 #?         (write-slice-buffered Stderr %ecx)
 6223 #?         (write-buffered Stderr "; var name ")
 6224 #?         (lookup *eax *(eax+4))  # Var-name
 6225 #?         (write-buffered Stderr %eax)
 6226 #?         (write-buffered Stderr Newline)
 6227 #?         (flush Stderr)
 6228         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 6229       }
 6230       # is-deref? = false
 6231       ba/copy-to-edx 0/imm32/false
 6232       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 6233       8b/-> *ecx 0/r32/eax  # Slice-start
 6234       8a/copy-byte *eax 0/r32/AL
 6235       81 4/subop/and %eax 0xff/imm32
 6236       3d/compare-eax-and 0x2a/imm32/asterisk
 6237       {
 6238         75/jump-if-!= break/disp8
 6239 $add-operation-and-inputs-to-stmt:inout-is-deref:
 6240         ff 0/subop/increment *ecx
 6241         ba/copy-to-edx 1/imm32/true
 6242       }
 6243       (lookup-var-or-literal %ecx *(ebp+0x10) %esi)
 6244 $add-operation-and-inputs-to-stmt:save-var:
 6245       8d/copy-address *(edi+0xc) 0/r32/eax
 6246       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 6247       #
 6248       e9/jump loop/disp32
 6249     }
 6250 $add-operation-and-inputs-to-stmt:end:
 6251     # . reclaim locals
 6252     81 0/subop/add %esp 0x10/imm32
 6253     # . restore registers
 6254     5f/pop-to-edi
 6255     5e/pop-to-esi
 6256     5b/pop-to-ebx
 6257     5a/pop-to-edx
 6258     59/pop-to-ecx
 6259     58/pop-to-eax
 6260     # . epilogue
 6261     89/<- %esp 5/r32/ebp
 6262     5d/pop-to-ebp
 6263     c3/return
 6264 
 6265 $add-operation-and-inputs-to-stmt:abort:
 6266     # error("invalid statement '" line "'\n")
 6267     (rewind-stream *(ebp+8))
 6268     (write-buffered Stderr "invalid identifier '")
 6269     (flush Stderr)
 6270     (write-stream 2 *(ebp+8))
 6271     (write-buffered Stderr "'\n")
 6272     (flush Stderr)
 6273     # . syscall(exit, 1)
 6274     bb/copy-to-ebx  1/imm32
 6275     b8/copy-to-eax  1/imm32/exit
 6276     cd/syscall  0x80/imm8
 6277     # never gets here
 6278 
 6279 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 6280     # . prologue
 6281     55/push-ebp
 6282     89/<- %ebp 4/r32/esp
 6283     # . save registers
 6284     51/push-ecx
 6285     # var word-slice/ecx: slice
 6286     68/push 0/imm32/end
 6287     68/push 0/imm32/start
 6288     89/<- %ecx 4/r32/esp
 6289     # result = false
 6290     b8/copy-to-eax 0/imm32/false
 6291     (rewind-stream *(ebp+8))
 6292     {
 6293       (next-mu-token *(ebp+8) %ecx)
 6294       # if slice-empty?(word-slice) break
 6295       (slice-empty? %ecx)
 6296       3d/compare-eax-and 0/imm32/false
 6297       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6298       0f 85/jump-if-!= break/disp32
 6299       # if slice-starts-with?(word-slice, '#') break
 6300       # . eax = *word-slice->start
 6301       8b/-> *ecx 0/r32/eax
 6302       8a/copy-byte *eax 0/r32/AL
 6303       81 4/subop/and %eax 0xff/imm32
 6304       # . if (eax == '#') break
 6305       3d/compare-eax-and 0x23/imm32/hash
 6306       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6307       0f 84/jump-if-= break/disp32
 6308       # if slice-equal?(word-slice, '<-') return true
 6309       (slice-equal? %ecx "<-")
 6310       3d/compare-eax-and 0/imm32/false
 6311       74/jump-if-= loop/disp8
 6312       b8/copy-to-eax 1/imm32/true
 6313     }
 6314 $stmt-has-outputs:end:
 6315     (rewind-stream *(ebp+8))
 6316     # . reclaim locals
 6317     81 0/subop/add %esp 8/imm32
 6318     # . restore registers
 6319     59/pop-to-ecx
 6320     # . epilogue
 6321     89/<- %esp 5/r32/ebp
 6322     5d/pop-to-ebp
 6323     c3/return
 6324 
 6325 # if 'name' starts with a digit, create a new literal var for it
 6326 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 6327 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var)
 6328     # . prologue
 6329     55/push-ebp
 6330     89/<- %ebp 4/r32/esp
 6331     # . save registers
 6332     50/push-eax
 6333     51/push-ecx
 6334     56/push-esi
 6335     # esi = name
 6336     8b/-> *(ebp+8) 6/r32/esi
 6337     # if slice-empty?(name) abort
 6338     (slice-empty? %esi)  # => eax
 6339     3d/compare-eax-and 0/imm32/false
 6340     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 6341     # var c/ecx: byte = *name->start
 6342     8b/-> *esi 1/r32/ecx
 6343     8a/copy-byte *ecx 1/r32/CL
 6344     81 4/subop/and %ecx 0xff/imm32
 6345     # if is-decimal-digit?(c) return new var(name)
 6346     {
 6347       (is-decimal-digit? %ecx)  # => eax
 6348       3d/compare-eax-and 0/imm32/false
 6349       74/jump-if-= break/disp8
 6350       (new-literal-integer Heap %esi *(ebp+0x10))
 6351       eb/jump $lookup-var-or-literal:end/disp8
 6352     }
 6353     # else if (c == '"') return new var(name)
 6354     {
 6355       81 7/subop/compare %ecx 0x22/imm32/dquote
 6356       75/jump-if-!= break/disp8
 6357       (new-literal Heap %esi *(ebp+0x10))
 6358       eb/jump $lookup-var-or-literal:end/disp8
 6359     }
 6360     # otherwise return lookup-var(name, vars)
 6361     {
 6362       (lookup-var %esi *(ebp+0xc))  # => eax
 6363     }
 6364 $lookup-var-or-literal:end:
 6365     # . restore registers
 6366     5e/pop-to-esi
 6367     59/pop-to-ecx
 6368     58/pop-to-eax
 6369     # . epilogue
 6370     89/<- %esp 5/r32/ebp
 6371     5d/pop-to-ebp
 6372     c3/return
 6373 
 6374 $lookup-var-or-literal:abort:
 6375     (write-buffered Stderr "empty variable!")
 6376     (flush Stderr)
 6377     # . syscall(exit, 1)
 6378     bb/copy-to-ebx  1/imm32
 6379     b8/copy-to-eax  1/imm32/exit
 6380     cd/syscall  0x80/imm8
 6381     # never gets here
 6382 
 6383 # return first 'name' from the top (back) of 'vars' and abort if not found
 6384 lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var)
 6385     # . prologue
 6386     55/push-ebp
 6387     89/<- %ebp 4/r32/esp
 6388     # . save registers
 6389     50/push-eax
 6390     #
 6391     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6392     # if (*out == 0) abort
 6393     8b/-> *(ebp+0x10) 0/r32/eax
 6394     81 7/subop/compare *eax 0/imm32
 6395     74/jump-if-= $lookup-var:abort/disp8
 6396 $lookup-var:end:
 6397     # . restore registers
 6398     58/pop-to-eax
 6399     # . epilogue
 6400     89/<- %esp 5/r32/ebp
 6401     5d/pop-to-ebp
 6402     c3/return
 6403 
 6404 $lookup-var:abort:
 6405     (write-buffered Stderr "unknown variable '")
 6406     (write-slice-buffered Stderr *(ebp+8))
 6407     (write-buffered Stderr "'\n")
 6408     (flush Stderr)
 6409     # . syscall(exit, 1)
 6410     bb/copy-to-ebx  1/imm32
 6411     b8/copy-to-eax  1/imm32/exit
 6412     cd/syscall  0x80/imm8
 6413     # never gets here
 6414 
 6415 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 6416 lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var)
 6417     # pseudocode:
 6418     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 6419     #   var min = vars->data
 6420     #   while curr >= min
 6421     #     var v: (handle var) = *curr
 6422     #     if v->name == name
 6423     #       return
 6424     #     curr -= 12
 6425     #
 6426     # . prologue
 6427     55/push-ebp
 6428     89/<- %ebp 4/r32/esp
 6429     # . save registers
 6430     50/push-eax
 6431     51/push-ecx
 6432     52/push-edx
 6433     53/push-ebx
 6434     56/push-esi
 6435     # clear out
 6436     (zero-out *(ebp+0x10) *Handle-size)
 6437     # esi = vars
 6438     8b/-> *(ebp+0xc) 6/r32/esi
 6439     # ebx = vars->top
 6440     8b/-> *esi 3/r32/ebx
 6441     # if (vars->top > vars->size) abort
 6442     3b/compare<- *(esi+4) 0/r32/eax
 6443     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 6444     # var min/edx: (addr handle var) = vars->data
 6445     8d/copy-address *(esi+8) 2/r32/edx
 6446     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 6447     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 6448     {
 6449       # if (curr < min) return
 6450       39/compare %ebx 2/r32/edx
 6451       0f 82/jump-if-addr< break/disp32
 6452       # var v/ecx: (addr var) = lookup(*curr)
 6453       (lookup *ebx *(ebx+4))  # => eax
 6454       89/<- %ecx 0/r32/eax
 6455       # var vn/eax: (addr array byte) = lookup(v->name)
 6456       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6457       # if (vn == name) return curr
 6458       (slice-equal? *(ebp+8) %eax)  # => eax
 6459       3d/compare-eax-and 0/imm32/false
 6460       {
 6461         74/jump-if-= break/disp8
 6462         # esi = out
 6463         8b/-> *(ebp+0x10) 6/r32/esi
 6464         # *out = *curr
 6465         8b/-> *ebx 0/r32/eax
 6466         89/<- *esi 0/r32/eax
 6467         8b/-> *(ebx+4) 0/r32/eax
 6468         89/<- *(esi+4) 0/r32/eax
 6469         # return
 6470         eb/jump $lookup-var-helper:end/disp8
 6471       }
 6472       # curr -= 12
 6473       81 5/subop/subtract %ebx 0xc/imm32
 6474       e9/jump loop/disp32
 6475     }
 6476 $lookup-var-helper:end:
 6477     # . restore registers
 6478     5e/pop-to-esi
 6479     5b/pop-to-ebx
 6480     5a/pop-to-edx
 6481     59/pop-to-ecx
 6482     58/pop-to-eax
 6483     # . epilogue
 6484     89/<- %esp 5/r32/ebp
 6485     5d/pop-to-ebp
 6486     c3/return
 6487 
 6488 $lookup-var-helper:error1:
 6489     (write-buffered Stderr "malformed stack when looking up '")
 6490     (write-slice-buffered Stderr *(ebp+8))
 6491     (write-buffered Stderr "'\n")
 6492     (flush Stderr)
 6493     # . syscall(exit, 1)
 6494     bb/copy-to-ebx  1/imm32
 6495     b8/copy-to-eax  1/imm32/exit
 6496     cd/syscall  0x80/imm8
 6497     # never gets here
 6498 
 6499 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 6500 lookup-or-define-var:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var)
 6501     # . prologue
 6502     55/push-ebp
 6503     89/<- %ebp 4/r32/esp
 6504     # . save registers
 6505     50/push-eax
 6506     #
 6507     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
 6508     {
 6509       # if (out != 0) return
 6510       8b/-> *(ebp+0x14) 0/r32/eax
 6511       81 7/subop/compare *eax 0/imm32
 6512       75/jump-if-!= break/disp8
 6513       # if name is one of fn's outputs, return it
 6514       {
 6515         (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 6516         8b/-> *(ebp+0x14) 0/r32/eax
 6517         81 7/subop/compare *eax 0/imm32
 6518         # otherwise abort
 6519         0f 84/jump-if-= $lookup-var:abort/disp32
 6520         # update vars
 6521         (push *(ebp+0xc) *eax)
 6522         (push *(ebp+0xc) *(eax+4))
 6523         (push *(ebp+0xc) 0)  # never spill fn-outputs
 6524       }
 6525     }
 6526 $lookup-or-define-var:end:
 6527     # . restore registers
 6528     58/pop-to-eax
 6529     # . epilogue
 6530     89/<- %esp 5/r32/ebp
 6531     5d/pop-to-ebp
 6532     c3/return
 6533 
 6534 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 6535     # . prologue
 6536     55/push-ebp
 6537     89/<- %ebp 4/r32/esp
 6538     # . save registers
 6539     50/push-eax
 6540     51/push-ecx
 6541     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 6542     8b/-> *(ebp+8) 1/r32/ecx
 6543     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 6544     89/<- %ecx 0/r32/eax
 6545     # while curr != null
 6546     {
 6547       81 7/subop/compare %ecx 0/imm32
 6548       74/jump-if-= break/disp8
 6549       # var v/eax: (addr var) = lookup(curr->value)
 6550       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 6551       # var s/eax: (addr array byte) = lookup(v->name)
 6552       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6553       # if (s == name) return curr->value
 6554       (slice-equal? *(ebp+0xc) %eax)  # => eax
 6555       3d/compare-eax-and 0/imm32/false
 6556       {
 6557         74/jump-if-= break/disp8
 6558         # var edi = out
 6559         57/push-edi
 6560         8b/-> *(ebp+0x10) 7/r32/edi
 6561         # *out = curr->value
 6562         8b/-> *ecx 0/r32/eax
 6563         89/<- *edi 0/r32/eax
 6564         8b/-> *(ecx+4) 0/r32/eax
 6565         89/<- *(edi+4) 0/r32/eax
 6566         #
 6567         5f/pop-to-edi
 6568         eb/jump $find-in-function-outputs:end/disp8
 6569       }
 6570       # curr = curr->next
 6571       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 6572       89/<- %ecx 0/r32/eax
 6573       #
 6574       eb/jump loop/disp8
 6575     }
 6576     b8/copy-to-eax 0/imm32
 6577 $find-in-function-outputs:end:
 6578     # . restore registers
 6579     59/pop-to-ecx
 6580     58/pop-to-eax
 6581     # . epilogue
 6582     89/<- %esp 5/r32/ebp
 6583     5d/pop-to-ebp
 6584     c3/return
 6585 
 6586 test-parse-mu-stmt:
 6587     # . prologue
 6588     55/push-ebp
 6589     89/<- %ebp 4/r32/esp
 6590     # setup
 6591     (clear-stream _test-input-stream)
 6592     (write _test-input-stream "increment n\n")
 6593     # var vars/ecx: (stack (addr var) 16)
 6594     81 5/subop/subtract %esp 0xc0/imm32
 6595     68/push 0xc0/imm32/size
 6596     68/push 0/imm32/top
 6597     89/<- %ecx 4/r32/esp
 6598     (clear-stack %ecx)
 6599     # var v/edx: (handle var)
 6600     68/push 0/imm32
 6601     68/push 0/imm32
 6602     89/<- %edx 4/r32/esp
 6603     # var s/eax: (handle array byte)
 6604     68/push 0/imm32
 6605     68/push 0/imm32
 6606     89/<- %eax 4/r32/esp
 6607     # v = new var("n")
 6608     (copy-array Heap "n" %eax)
 6609     (new-var Heap *eax *(eax+4) %edx)
 6610     #
 6611     (push %ecx *edx)
 6612     (push %ecx *(edx+4))
 6613     (push %ecx 0)
 6614     # var out/eax: (handle stmt)
 6615     68/push 0/imm32
 6616     68/push 0/imm32
 6617     89/<- %eax 4/r32/esp
 6618     # convert
 6619     (parse-mu-stmt _test-input-stream %ecx 0 %eax)
 6620     # var out-addr/edx: (addr stmt) = lookup(*out)
 6621     (lookup *eax *(eax+4))  # => eax
 6622     89/<- %edx 0/r32/eax
 6623     # out->tag
 6624     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 6625     # out->operation
 6626     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6627     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 6628     # out->inouts->value->name
 6629     # . eax = out->inouts
 6630     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6631     # . eax = out->inouts->value
 6632     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6633     # . eax = out->inouts->value->name
 6634     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6635     # .
 6636     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 6637     # . epilogue
 6638     89/<- %esp 5/r32/ebp
 6639     5d/pop-to-ebp
 6640     c3/return
 6641 
 6642 test-parse-mu-stmt-with-comma:
 6643     # . prologue
 6644     55/push-ebp
 6645     89/<- %ebp 4/r32/esp
 6646     # setup
 6647     (clear-stream _test-input-stream)
 6648     (write _test-input-stream "copy-to n, 3\n")
 6649     # var vars/ecx: (stack (addr var) 16)
 6650     81 5/subop/subtract %esp 0xc0/imm32
 6651     68/push 0xc0/imm32/size
 6652     68/push 0/imm32/top
 6653     89/<- %ecx 4/r32/esp
 6654     (clear-stack %ecx)
 6655     # var v/edx: (handle var)
 6656     68/push 0/imm32
 6657     68/push 0/imm32
 6658     89/<- %edx 4/r32/esp
 6659     # var s/eax: (handle array byte)
 6660     68/push 0/imm32
 6661     68/push 0/imm32
 6662     89/<- %eax 4/r32/esp
 6663     # v = new var("n")
 6664     (copy-array Heap "n" %eax)
 6665     (new-var Heap *eax *(eax+4) %edx)
 6666     #
 6667     (push %ecx *edx)
 6668     (push %ecx *(edx+4))
 6669     (push %ecx 0)
 6670     # var out/eax: (handle stmt)
 6671     68/push 0/imm32
 6672     68/push 0/imm32
 6673     89/<- %eax 4/r32/esp
 6674     # convert
 6675     (parse-mu-stmt _test-input-stream %ecx 0 %eax)
 6676     # var out-addr/edx: (addr stmt) = lookup(*out)
 6677     (lookup *eax *(eax+4))  # => eax
 6678     89/<- %edx 0/r32/eax
 6679     # out->tag
 6680     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 6681     # out->operation
 6682     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6683     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 6684     # out->inouts->value->name
 6685     # . eax = out->inouts
 6686     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6687     # . eax = out->inouts->value
 6688     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6689     # . eax = out->inouts->value->name
 6690     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6691     # .
 6692     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 6693     # . epilogue
 6694     89/<- %esp 5/r32/ebp
 6695     5d/pop-to-ebp
 6696     c3/return
 6697 
 6698 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 6699     # . prologue
 6700     55/push-ebp
 6701     89/<- %ebp 4/r32/esp
 6702     # . save registers
 6703     50/push-eax
 6704     51/push-ecx
 6705     # ecx = out
 6706     8b/-> *(ebp+0x14) 1/r32/ecx
 6707     #
 6708     (allocate *(ebp+8) *Var-size %ecx)
 6709     # var out-addr/eax: (addr var)
 6710     (lookup *ecx *(ecx+4))  # => eax
 6711     # out-addr->name = name
 6712     8b/-> *(ebp+0xc) 1/r32/ecx
 6713     89/<- *eax 1/r32/ecx  # Var-name
 6714     8b/-> *(ebp+0x10) 1/r32/ecx
 6715     89/<- *(eax+4) 1/r32/ecx  # Var-name
 6716 #?     (write-buffered Stderr "var ")
 6717 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 6718 #?     (write-buffered Stderr %eax)
 6719 #?     (write-buffered Stderr " at ")
 6720 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 6721 #?     (lookup *ecx *(ecx+4))  # => eax
 6722 #?     (print-int32-buffered Stderr %eax)
 6723 #?     (write-buffered Stderr Newline)
 6724 #?     (flush Stderr)
 6725 $new-var:end:
 6726     # . restore registers
 6727     59/pop-to-ecx
 6728     58/pop-to-eax
 6729     # . epilogue
 6730     89/<- %esp 5/r32/ebp
 6731     5d/pop-to-ebp
 6732     c3/return
 6733 
 6734 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6735     # . prologue
 6736     55/push-ebp
 6737     89/<- %ebp 4/r32/esp
 6738     # . save registers
 6739     50/push-eax
 6740     51/push-ecx
 6741     # if (!is-hex-int?(name)) abort
 6742     (is-hex-int? *(ebp+0xc))  # => eax
 6743     3d/compare-eax-and 0/imm32/false
 6744     0f 84/jump-if-= $new-literal-integer:abort/disp32
 6745     # out = new var(s)
 6746     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6747     # var out-addr/ecx: (addr var) = lookup(*out)
 6748     8b/-> *(ebp+0x10) 0/r32/eax
 6749     (lookup *eax *(eax+4))  # => eax
 6750     89/<- %ecx 0/r32/eax
 6751     # out-addr->type = new tree()
 6752     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6753     (allocate *(ebp+8) *Tree-size %eax)
 6754     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6755     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6756     # nothing else to do; default type is 'literal'
 6757 $new-literal-integer:end:
 6758     # . reclaim locals
 6759     81 0/subop/add %esp 8/imm32
 6760     # . restore registers
 6761     59/pop-to-ecx
 6762     58/pop-to-eax
 6763     # . epilogue
 6764     89/<- %esp 5/r32/ebp
 6765     5d/pop-to-ebp
 6766     c3/return
 6767 
 6768 $new-literal-integer:abort:
 6769     (write-buffered Stderr "variable cannot begin with a digit '")
 6770     (write-slice-buffered Stderr *(ebp+0xc))
 6771     (write-buffered Stderr "'\n")
 6772     (flush Stderr)
 6773     # . syscall(exit, 1)
 6774     bb/copy-to-ebx  1/imm32
 6775     b8/copy-to-eax  1/imm32/exit
 6776     cd/syscall  0x80/imm8
 6777     # never gets here
 6778 
 6779 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6780     # . prologue
 6781     55/push-ebp
 6782     89/<- %ebp 4/r32/esp
 6783     # . save registers
 6784     50/push-eax
 6785     51/push-ecx
 6786     # var s/ecx: (handle array byte)
 6787     68/push 0/imm32
 6788     68/push 0/imm32
 6789     89/<- %ecx 4/r32/esp
 6790     # s = slice-to-string(name)
 6791     (slice-to-string Heap *(ebp+0xc) %ecx)
 6792     # allocate to out
 6793     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6794     # var out-addr/ecx: (addr var) = lookup(*out)
 6795     8b/-> *(ebp+0x10) 1/r32/ecx
 6796     (lookup *ecx *(ecx+4))  # => eax
 6797     89/<- %ecx 0/r32/eax
 6798     # out-addr->type/eax = new type
 6799     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6800     (allocate *(ebp+8) *Tree-size %eax)
 6801     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6802     # nothing else to do; default type is 'literal'
 6803     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6804 $new-literal:end:
 6805     # . reclaim locals
 6806     81 0/subop/add %esp 8/imm32
 6807     # . restore registers
 6808     59/pop-to-ecx
 6809     58/pop-to-eax
 6810     # . epilogue
 6811     89/<- %esp 5/r32/ebp
 6812     5d/pop-to-ebp
 6813     c3/return
 6814 
 6815 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6816     # . prologue
 6817     55/push-ebp
 6818     89/<- %ebp 4/r32/esp
 6819     # . save registers
 6820     51/push-ecx
 6821     # var tmp/ecx: (handle array byte)
 6822     68/push 0/imm32
 6823     68/push 0/imm32
 6824     89/<- %ecx 4/r32/esp
 6825     # tmp = slice-to-string(name)
 6826     (slice-to-string Heap *(ebp+0xc) %ecx)
 6827     # out = new-var(tmp)
 6828     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6829 $new-var-from-slice:end:
 6830     # . reclaim locals
 6831     81 0/subop/add %esp 8/imm32
 6832     # . restore registers
 6833     59/pop-to-ecx
 6834     # . epilogue
 6835     89/<- %esp 5/r32/ebp
 6836     5d/pop-to-ebp
 6837     c3/return
 6838 
 6839 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 6840     # . prologue
 6841     55/push-ebp
 6842     89/<- %ebp 4/r32/esp
 6843     # . save registers
 6844     50/push-eax
 6845     51/push-ecx
 6846     #
 6847     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 6848     # var out-addr/eax: (addr stmt) = lookup(*out)
 6849     8b/-> *(ebp+0x14) 0/r32/eax
 6850     (lookup *eax *(eax+4))  # => eax
 6851     # out-addr->tag = stmt
 6852     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 6853     # result->var = var
 6854     8b/-> *(ebp+0xc) 1/r32/ecx
 6855     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 6856     8b/-> *(ebp+0x10) 1/r32/ecx
 6857     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 6858 $new-var-def:end:
 6859     # . restore registers
 6860     59/pop-to-ecx
 6861     58/pop-to-eax
 6862     # . epilogue
 6863     89/<- %esp 5/r32/ebp
 6864     5d/pop-to-ebp
 6865     c3/return
 6866 
 6867 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 6868     # . prologue
 6869     55/push-ebp
 6870     89/<- %ebp 4/r32/esp
 6871     # . save registers
 6872     50/push-eax
 6873     # eax = out
 6874     8b/-> *(ebp+0x14) 0/r32/eax
 6875     #
 6876     (allocate *(ebp+8) *Stmt-size %eax)
 6877     # var out-addr/eax: (addr stmt) = lookup(*out)
 6878     (lookup *eax *(eax+4))  # => eax
 6879     # set tag
 6880     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 6881     # set output
 6882     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 6883     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 6884 $new-reg-var-def:end:
 6885     # . restore registers
 6886     58/pop-to-eax
 6887     # . epilogue
 6888     89/<- %esp 5/r32/ebp
 6889     5d/pop-to-ebp
 6890     c3/return
 6891 
 6892 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 6893     # . prologue
 6894     55/push-ebp
 6895     89/<- %ebp 4/r32/esp
 6896     # . save registers
 6897     50/push-eax
 6898     51/push-ecx
 6899     57/push-edi
 6900     # edi = out
 6901     8b/-> *(ebp+0x1c) 7/r32/edi
 6902     # *out = new list
 6903     (allocate *(ebp+8) *List-size %edi)
 6904     # var out-addr/edi: (addr list _type) = lookup(*out)
 6905     (lookup *edi *(edi+4))  # => eax
 6906     89/<- %edi 0/r32/eax
 6907     # out-addr->value = value
 6908     8b/-> *(ebp+0xc) 0/r32/eax
 6909     89/<- *edi 0/r32/eax  # List-value
 6910     8b/-> *(ebp+0x10) 0/r32/eax
 6911     89/<- *(edi+4) 0/r32/eax  # List-value
 6912     # if (list == null) return
 6913     81 7/subop/compare *(ebp+0x14) 0/imm32
 6914     74/jump-if-= $append-list:end/disp8
 6915     # otherwise append
 6916 $append-list:non-empty-list:
 6917     # var curr/eax: (addr list _type) = lookup(list)
 6918     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 6919     # while (curr->next != null) curr = curr->next
 6920     {
 6921       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 6922       74/jump-if-= break/disp8
 6923       # curr = lookup(curr->next)
 6924       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 6925       #
 6926       eb/jump loop/disp8
 6927     }
 6928     # edi = out
 6929     8b/-> *(ebp+0x1c) 7/r32/edi
 6930     # curr->next = out
 6931     8b/-> *edi 1/r32/ecx
 6932     89/<- *(eax+8) 1/r32/ecx  # List-next
 6933     8b/-> *(edi+4) 1/r32/ecx
 6934     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 6935     # out = list
 6936     8b/-> *(ebp+0x14) 1/r32/ecx
 6937     89/<- *edi 1/r32/ecx
 6938     8b/-> *(ebp+0x18) 1/r32/ecx
 6939     89/<- *(edi+4) 1/r32/ecx
 6940 $append-list:end:
 6941     # . restore registers
 6942     5f/pop-to-edi
 6943     59/pop-to-ecx
 6944     58/pop-to-eax
 6945     # . epilogue
 6946     89/<- %esp 5/r32/ebp
 6947     5d/pop-to-ebp
 6948     c3/return
 6949 
 6950 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 6951     # . prologue
 6952     55/push-ebp
 6953     89/<- %ebp 4/r32/esp
 6954     # . save registers
 6955     50/push-eax
 6956     51/push-ecx
 6957     57/push-edi
 6958     # edi = out
 6959     8b/-> *(ebp+0x20) 7/r32/edi
 6960     # out = new stmt-var
 6961     (allocate *(ebp+8) *Stmt-var-size %edi)
 6962     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 6963     (lookup *edi *(edi+4))  # => eax
 6964     89/<- %ecx 0/r32/eax
 6965     # out-addr->value = v
 6966     8b/-> *(ebp+0xc) 0/r32/eax
 6967     89/<- *ecx 0/r32/eax  # Stmt-var-value
 6968     8b/-> *(ebp+0x10) 0/r32/eax
 6969     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 6970     # out-addr->is-deref? = is-deref?
 6971     8b/-> *(ebp+0x1c) 0/r32/eax
 6972     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 6973     # if (vars == null) return result
 6974     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 6975     74/jump-if-= $append-stmt-var:end/disp8
 6976     # otherwise append
 6977     # var curr/eax: (addr stmt-var) = lookup(vars)
 6978     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 6979     # while (curr->next != null) curr = curr->next
 6980     {
 6981       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 6982       74/jump-if-= break/disp8
 6983       # curr = lookup(curr->next)
 6984       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 6985       #
 6986       eb/jump loop/disp8
 6987     }
 6988     # curr->next = out
 6989     8b/-> *edi 1/r32/ecx
 6990     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 6991     8b/-> *(edi+4) 1/r32/ecx
 6992     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 6993     # out = vars
 6994     8b/-> *(ebp+0x14) 1/r32/ecx
 6995     89/<- *edi 1/r32/ecx
 6996     8b/-> *(ebp+0x18) 1/r32/ecx
 6997     89/<- *(edi+4) 1/r32/ecx
 6998 $append-stmt-var:end:
 6999     # . restore registers
 7000     5f/pop-to-edi
 7001     59/pop-to-ecx
 7002     58/pop-to-eax
 7003     # . epilogue
 7004     89/<- %esp 5/r32/ebp
 7005     5d/pop-to-ebp
 7006     c3/return
 7007 
 7008 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 7009     # . prologue
 7010     55/push-ebp
 7011     89/<- %ebp 4/r32/esp
 7012     # . save registers
 7013     50/push-eax
 7014     56/push-esi
 7015     # esi = block
 7016     8b/-> *(ebp+0xc) 6/r32/esi
 7017     # block->stmts = append(x, block->stmts)
 7018     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 7019     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 7020 $append-to-block:end:
 7021     # . restore registers
 7022     5e/pop-to-esi
 7023     58/pop-to-eax
 7024     # . epilogue
 7025     89/<- %esp 5/r32/ebp
 7026     5d/pop-to-ebp
 7027     c3/return
 7028 
 7029 ## Parsing types
 7030 # We need to create metadata on user-defined types, and we need to use this
 7031 # metadata as we parse instructions.
 7032 # However, we also want to allow types to be used before their definitions.
 7033 # This means we can't ever assume any type data structures exist.
 7034 
 7035 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 7036     # . prologue
 7037     55/push-ebp
 7038     89/<- %ebp 4/r32/esp
 7039     # . save registers
 7040     50/push-eax
 7041     56/push-esi
 7042     # var container-type/esi: type-id
 7043     (container-type *(ebp+8))  # => eax
 7044     89/<- %esi 0/r32/eax
 7045     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 7046     68/push 0/imm32
 7047     68/push 0/imm32
 7048     89/<- %eax 4/r32/esp
 7049     (find-or-create-typeinfo %esi %eax)
 7050     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 7051     (lookup *eax *(eax+4))  # => eax
 7052     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 7053 #?     (write-buffered Stderr "constant: ")
 7054 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7055 #?     (write-buffered Stderr Newline)
 7056 #?     (flush Stderr)
 7057     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 7058 #?     8b/-> *(ebp+0x10) 0/r32/eax
 7059 #?     (write-buffered Stderr "@")
 7060 #?     (lookup *eax *(eax+4))
 7061 #?     (print-int32-buffered Stderr %eax)
 7062 #?     (lookup *eax *(eax+4))
 7063 #?     (write-buffered Stderr %eax)
 7064 #?     (write-buffered Stderr Newline)
 7065 #?     (flush Stderr)
 7066 #?     (write-buffered Stderr "offset: ")
 7067 #?     8b/-> *(eax+0x14) 0/r32/eax
 7068 #?     (print-int32-buffered Stderr %eax)
 7069 #?     (write-buffered Stderr Newline)
 7070 #?     (flush Stderr)
 7071 $lookup-or-create-constant:end:
 7072     # . reclaim locals
 7073     81 0/subop/add %esp 8/imm32
 7074     # . restore registers
 7075     5e/pop-to-esi
 7076     58/pop-to-eax
 7077     # . epilogue
 7078     89/<- %esp 5/r32/ebp
 7079     5d/pop-to-ebp
 7080     c3/return
 7081 
 7082 # if addr var:
 7083 #   container->var->type->right->left->value
 7084 # otherwise
 7085 #   container->var->type->value
 7086 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 7087     # . prologue
 7088     55/push-ebp
 7089     89/<- %ebp 4/r32/esp
 7090     #
 7091     8b/-> *(ebp+8) 0/r32/eax
 7092     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7093     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 7094     {
 7095       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 7096       74/jump-if-= break/disp8
 7097       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 7098       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 7099     }
 7100     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 7101 $container-type:end:
 7102     # . epilogue
 7103     89/<- %esp 5/r32/ebp
 7104     5d/pop-to-ebp
 7105     c3/return
 7106 
 7107 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 7108     # . prologue
 7109     55/push-ebp
 7110     89/<- %ebp 4/r32/esp
 7111     # . save registers
 7112     50/push-eax
 7113     51/push-ecx
 7114     52/push-edx
 7115     57/push-edi
 7116     # edi = out
 7117     8b/-> *(ebp+0xc) 7/r32/edi
 7118     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 7119     68/push 0/imm32
 7120     68/push 0/imm32
 7121     89/<- %ecx 4/r32/esp
 7122     # find-typeinfo(t, out)
 7123     (find-typeinfo *(ebp+8) %edi)
 7124     {
 7125       # if (*out != 0) break
 7126       81 7/subop/compare *edi 0/imm32
 7127       0f 85/jump-if-!= break/disp32
 7128 $find-or-create-typeinfo:create:
 7129       # *out = allocate
 7130       (allocate Heap *Typeinfo-size %edi)
 7131       # var tmp/eax: (addr typeinfo) = lookup(*out)
 7132       (lookup *edi *(edi+4))  # => eax
 7133 #?     (write-buffered Stderr "created typeinfo at ")
 7134 #?     (print-int32-buffered Stderr %eax)
 7135 #?     (write-buffered Stderr " for type-id ")
 7136 #?     (print-int32-buffered Stderr *(ebp+8))
 7137 #?     (write-buffered Stderr Newline)
 7138 #?     (flush Stderr)
 7139       # tmp->id = t
 7140       8b/-> *(ebp+8) 2/r32/edx
 7141       89/<- *eax 2/r32/edx  # Typeinfo-id
 7142       # tmp->fields = new table
 7143       # . fields = new table
 7144       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 7145       # . tmp->fields = fields
 7146       8b/-> *ecx 2/r32/edx
 7147       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 7148       8b/-> *(ecx+4) 2/r32/edx
 7149       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 7150       # tmp->next = Program->types
 7151       8b/-> *_Program-types 1/r32/ecx
 7152       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 7153       8b/-> *_Program-types->payload 1/r32/ecx
 7154       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 7155       # Program->types = out
 7156       8b/-> *edi 1/r32/ecx
 7157       89/<- *_Program-types 1/r32/ecx
 7158       8b/-> *(edi+4) 1/r32/ecx
 7159       89/<- *_Program-types->payload 1/r32/ecx
 7160     }
 7161 $find-or-create-typeinfo:end:
 7162     # . reclaim locals
 7163     81 0/subop/add %esp 8/imm32
 7164     # . restore registers
 7165     5f/pop-to-edi
 7166     5a/pop-to-edx
 7167     59/pop-to-ecx
 7168     58/pop-to-eax
 7169     # . epilogue
 7170     89/<- %esp 5/r32/ebp
 7171     5d/pop-to-ebp
 7172     c3/return
 7173 
 7174 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 7175     # . prologue
 7176     55/push-ebp
 7177     89/<- %ebp 4/r32/esp
 7178     # . save registers
 7179     50/push-eax
 7180     51/push-ecx
 7181     52/push-edx
 7182     57/push-edi
 7183     # ecx = t
 7184     8b/-> *(ebp+8) 1/r32/ecx
 7185     # edi = out
 7186     8b/-> *(ebp+0xc) 7/r32/edi
 7187     # *out = Program->types
 7188     8b/-> *_Program-types 0/r32/eax
 7189     89/<- *edi 0/r32/eax
 7190     8b/-> *_Program-types->payload 0/r32/eax
 7191     89/<- *(edi+4) 0/r32/eax
 7192     {
 7193       # if (*out == 0) break
 7194       81 7/subop/compare *edi 0/imm32
 7195       74/jump-if-= break/disp8
 7196       # var tmp/eax: (addr typeinfo) = lookup(*out)
 7197       (lookup *edi *(edi+4))  # => eax
 7198       # if (tmp->id == t) break
 7199       39/compare *eax 1/r32/ecx  # Typeinfo-id
 7200       74/jump-if-= break/disp8
 7201       # *out = tmp->next
 7202       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 7203       89/<- *edi 2/r32/edx
 7204       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 7205       89/<- *(edi+4) 2/r32/edx
 7206       #
 7207       eb/jump loop/disp8
 7208     }
 7209 $find-typeinfo:end:
 7210     # . restore registers
 7211     5f/pop-to-edi
 7212     5a/pop-to-edx
 7213     59/pop-to-ecx
 7214     58/pop-to-eax
 7215     # . epilogue
 7216     89/<- %esp 5/r32/ebp
 7217     5d/pop-to-ebp
 7218     c3/return
 7219 
 7220 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 7221     # . prologue
 7222     55/push-ebp
 7223     89/<- %ebp 4/r32/esp
 7224     # . save registers
 7225     50/push-eax
 7226     52/push-edx
 7227     57/push-edi
 7228     # var dest/edi: (handle typeinfo-entry)
 7229     68/push 0/imm32
 7230     68/push 0/imm32
 7231     89/<- %edi 4/r32/esp
 7232     # find-or-create-typeinfo-fields(T, f, dest)
 7233     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 7234     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 7235     (lookup *edi *(edi+4))  # => eax
 7236     89/<- %edi 0/r32/eax
 7237     # if dest-addr->output-var doesn't exist, create it
 7238     {
 7239       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 7240       0f 85/jump-if-!= break/disp32
 7241       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 7242       # . var name/eax: (handle array byte) = "field"
 7243       68/push 0/imm32
 7244       68/push 0/imm32
 7245       89/<- %eax 4/r32/esp
 7246       (copy-array Heap "field" %eax)
 7247       # . new var
 7248       8d/copy-address *(edi+0xc) 2/r32/edx
 7249       (new-var Heap  *eax *(eax+4)  %edx)
 7250       # . reclaim name
 7251       81 0/subop/add %esp 8/imm32
 7252       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 7253       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 7254       89/<- %edx 0/r32/eax
 7255       # result->type = new constant type
 7256       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 7257       (allocate Heap *Tree-size %eax)
 7258       (lookup *(edx+8) *(edx+0xc))  # => eax
 7259       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 7260       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 7261       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 7262       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 7263       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 7264       # result->offset isn't filled out yet
 7265       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 7266     }
 7267     # out = dest-addr->output-var
 7268     8b/-> *(ebp+0x10) 2/r32/edx
 7269     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7270     89/<- *edx 0/r32/eax
 7271     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 7272     89/<- *(edx+4) 0/r32/eax
 7273 $find-or-create-typeinfo-output-var:end:
 7274     # . reclaim locals
 7275     81 0/subop/add %esp 8/imm32
 7276     # . restore registers
 7277     5f/pop-to-edi
 7278     5a/pop-to-edx
 7279     58/pop-to-eax
 7280     # . epilogue
 7281     89/<- %esp 5/r32/ebp
 7282     5d/pop-to-ebp
 7283     c3/return
 7284 
 7285 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 7286     # . prologue
 7287     55/push-ebp
 7288     89/<- %ebp 4/r32/esp
 7289     # . save registers
 7290     50/push-eax
 7291     56/push-esi
 7292     57/push-edi
 7293     # eax = lookup(T->fields)
 7294     8b/-> *(ebp+8) 0/r32/eax
 7295     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 7296     # edi = out
 7297     8b/-> *(ebp+0x10) 7/r32/edi
 7298     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 7299     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 7300     89/<- %esi 0/r32/eax
 7301     # if src doesn't exist, allocate it
 7302     {
 7303       81 7/subop/compare *esi 0/imm32
 7304       75/jump-if-!= break/disp8
 7305       (allocate Heap *Typeinfo-entry-size %esi)
 7306 #?       (write-buffered Stderr "handle at ")
 7307 #?       (print-int32-buffered Stderr %esi)
 7308 #?       (write-buffered Stderr ": ")
 7309 #?       (print-int32-buffered Stderr *esi)
 7310 #?       (write-buffered Stderr " ")
 7311 #?       (print-int32-buffered Stderr *(esi+4))
 7312 #?       (write-buffered Stderr Newline)
 7313 #?       (flush Stderr)
 7314 #?       (lookup *esi *(esi+4))
 7315 #?       (write-buffered Stderr "created typeinfo fields at ")
 7316 #?       (print-int32-buffered Stderr %esi)
 7317 #?       (write-buffered Stderr " for ")
 7318 #?       (print-int32-buffered Stderr *(ebp+8))
 7319 #?       (write-buffered Stderr Newline)
 7320 #?       (flush Stderr)
 7321     }
 7322     # *out = src
 7323     # . *edi = *src
 7324     8b/-> *esi 0/r32/eax
 7325     89/<- *edi 0/r32/eax
 7326     8b/-> *(esi+4) 0/r32/eax
 7327     89/<- *(edi+4) 0/r32/eax
 7328 $find-or-create-typeinfo-fields:end:
 7329     # . restore registers
 7330     5f/pop-to-edi
 7331     5e/pop-to-esi
 7332     58/pop-to-eax
 7333     # . epilogue
 7334     89/<- %esp 5/r32/ebp
 7335     5d/pop-to-ebp
 7336     c3/return
 7337 
 7338 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo)
 7339     # pseudocode:
 7340     #   var line: (stream byte 512)
 7341     #   curr-index = 0
 7342     #   while true
 7343     #     clear-stream(line)
 7344     #     read-line-buffered(in, line)
 7345     #     if line->write == 0
 7346     #       abort
 7347     #     word-slice = next-mu-token(line)
 7348     #     if slice-empty?(word-slice)               # end of line
 7349     #       continue
 7350     #     if slice-equal?(word-slice, "}")
 7351     #       break
 7352     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 7353     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 7354     #     TODO: ensure that r->first is null
 7355     #     r->index = curr-index
 7356     #     curr-index++
 7357     #     r->input-var = v
 7358     #     if r->output-var == 0
 7359     #       r->output-var = new literal
 7360     #     TODO: ensure nothing else in line
 7361     # t->total-size-in-bytes = -2 (not yet initialized)
 7362     #
 7363     # . prologue
 7364     55/push-ebp
 7365     89/<- %ebp 4/r32/esp
 7366     # var curr-index: int at *(ebp-4)
 7367     68/push 0/imm32
 7368     # . save registers
 7369     50/push-eax
 7370     51/push-ecx
 7371     52/push-edx
 7372     53/push-ebx
 7373     56/push-esi
 7374     57/push-edi
 7375     # edi = t
 7376     8b/-> *(ebp+0xc) 7/r32/edi
 7377     # var line/ecx: (stream byte 512)
 7378     81 5/subop/subtract %esp 0x200/imm32
 7379     68/push 0x200/imm32/size
 7380     68/push 0/imm32/read
 7381     68/push 0/imm32/write
 7382     89/<- %ecx 4/r32/esp
 7383     # var word-slice/edx: slice
 7384     68/push 0/imm32/end
 7385     68/push 0/imm32/start
 7386     89/<- %edx 4/r32/esp
 7387     # var v/esi: (handle var)
 7388     68/push 0/imm32
 7389     68/push 0/imm32
 7390     89/<- %esi 4/r32/esp
 7391     # var r/ebx: (handle typeinfo-entry)
 7392     68/push 0/imm32
 7393     68/push 0/imm32
 7394     89/<- %ebx 4/r32/esp
 7395     {
 7396 $populate-mu-type:line-loop:
 7397       (clear-stream %ecx)
 7398       (read-line-buffered *(ebp+8) %ecx)
 7399       # if (line->write == 0) abort
 7400       81 7/subop/compare *ecx 0/imm32
 7401       0f 84/jump-if-= $populate-mu-type:abort/disp32
 7402 +--  6 lines: #?       # dump line -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 7408       (next-mu-token %ecx %edx)
 7409       # if slice-empty?(word-slice) continue
 7410       (slice-empty? %edx)  # => eax
 7411       3d/compare-eax-and 0/imm32
 7412       0f 85/jump-if-!= loop/disp32
 7413       # if slice-equal?(word-slice, "}") break
 7414       (slice-equal? %edx "}")
 7415       3d/compare-eax-and 0/imm32
 7416       0f 85/jump-if-!= break/disp32
 7417 $populate-mu-type:parse-element:
 7418       # v = parse-var-with-type(word-slice, first-line)
 7419       # must do this first to strip the trailing ':' from word-slice before
 7420       # using it in find-or-create-typeinfo-fields below
 7421       # TODO: clean up that mutation in parse-var-with-type
 7422       (parse-var-with-type %edx %ecx %esi)  # => eax
 7423       # var tmp/ecx
 7424       51/push-ecx
 7425 $populate-mu-type:create-typeinfo-fields:
 7426       # var r/ebx: (handle typeinfo-entry)
 7427       (find-or-create-typeinfo-fields %edi %edx %ebx)
 7428       # r->index = curr-index
 7429       (lookup *ebx *(ebx+4))  # => eax
 7430       8b/-> *(ebp-4) 1/r32/ecx
 7431 #?       (write-buffered Stderr "saving index ")
 7432 #?       (print-int32-buffered Stderr %ecx)
 7433 #?       (write-buffered Stderr " at ")
 7434 #?       (print-int32-buffered Stderr %edi)
 7435 #?       (write-buffered Stderr Newline)
 7436 #?       (flush Stderr)
 7437       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 7438       # ++curr-index
 7439       ff 0/subop/increment *(ebp-4)
 7440 $populate-mu-type:set-input-type:
 7441       # r->input-var = v
 7442       8b/-> *esi 1/r32/ecx
 7443       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 7444       8b/-> *(esi+4) 1/r32/ecx
 7445       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 7446       59/pop-to-ecx
 7447       {
 7448 $populate-mu-type:create-output-type:
 7449         # if (r->output-var == 0) create a new var with some placeholder data
 7450         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 7451         75/jump-if-!= break/disp8
 7452         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7453         (new-literal Heap %edx %eax)
 7454       }
 7455       e9/jump loop/disp32
 7456     }
 7457 $populate-mu-type:invalidate-total-size-in-bytes:
 7458     # Offsets and total size may not be accurate here since we may not yet
 7459     # have encountered the element types.
 7460     # We'll recompute them separately after parsing the entire program.
 7461     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 7462 $populate-mu-type:end:
 7463     # . reclaim locals
 7464     81 0/subop/add %esp 0x224/imm32
 7465     # . restore registers
 7466     5f/pop-to-edi
 7467     5e/pop-to-esi
 7468     5b/pop-to-ebx
 7469     5a/pop-to-edx
 7470     59/pop-to-ecx
 7471     58/pop-to-eax
 7472     # reclaim curr-index
 7473     81 0/subop/add %esp 4/imm32
 7474     # . epilogue
 7475     89/<- %esp 5/r32/ebp
 7476     5d/pop-to-ebp
 7477     c3/return
 7478 
 7479 $populate-mu-type:abort:
 7480     # error("unexpected top-level command: " word-slice "\n")
 7481     (write-buffered Stderr "incomplete type definition '")
 7482     (type-name *edi)  # Typeinfo-id => eax
 7483     (write-buffered Stderr %eax)
 7484     (write-buffered Stderr "\n")
 7485     (flush Stderr)
 7486     # . syscall(exit, 1)
 7487     bb/copy-to-ebx  1/imm32
 7488     b8/copy-to-eax  1/imm32/exit
 7489     cd/syscall  0x80/imm8
 7490     # never gets here
 7491 
 7492 type-name:  # index: int -> result/eax: (addr array byte)
 7493     # . prologue
 7494     55/push-ebp
 7495     89/<- %ebp 4/r32/esp
 7496     #
 7497     (index Type-id *(ebp+8))
 7498 $type-name:end:
 7499     # . epilogue
 7500     89/<- %esp 5/r32/ebp
 7501     5d/pop-to-ebp
 7502     c3/return
 7503 
 7504 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 7505     # . prologue
 7506     55/push-ebp
 7507     89/<- %ebp 4/r32/esp
 7508     # . save registers
 7509     56/push-esi
 7510     # TODO: bounds-check index
 7511     # esi = arr
 7512     8b/-> *(ebp+8) 6/r32/esi
 7513     # eax = index
 7514     8b/-> *(ebp+0xc) 0/r32/eax
 7515     # eax = *(arr + 12 + index)
 7516     8b/-> *(esi+eax+0xc) 0/r32/eax
 7517 $index:end:
 7518     # . restore registers
 7519     5e/pop-to-esi
 7520     # . epilogue
 7521     89/<- %esp 5/r32/ebp
 7522     5d/pop-to-ebp
 7523     c3/return
 7524 
 7525 #######################################################
 7526 # Compute type sizes
 7527 #######################################################
 7528 
 7529 # Compute the sizes of all user-defined types.
 7530 # We'll need the sizes of their elements, which may be other user-defined
 7531 # types, which we will compute as needed.
 7532 
 7533 # Initially, all user-defined types have their sizes set to -2 (invalid)
 7534 populate-mu-type-sizes:
 7535     # . prologue
 7536     55/push-ebp
 7537     89/<- %ebp 4/r32/esp
 7538 $populate-mu-type-sizes:total-sizes:
 7539     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 7540     (lookup *_Program-types *_Program-types->payload)  # => eax
 7541     {
 7542       # if (curr == null) break
 7543       3d/compare-eax-and 0/imm32/null
 7544       74/jump-if-= break/disp8
 7545       (populate-mu-type-sizes-in-type %eax)
 7546       # curr = lookup(curr->next)
 7547       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7548       eb/jump loop/disp8
 7549     }
 7550 $populate-mu-type-sizes:offsets:
 7551     # curr = *Program->types
 7552     (lookup *_Program-types *_Program-types->payload)  # => eax
 7553     {
 7554       # if (curr == null) break
 7555       3d/compare-eax-and 0/imm32/null
 7556       74/jump-if-= break/disp8
 7557       (populate-mu-type-offsets %eax)
 7558       # curr = curr->next
 7559       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7560       eb/jump loop/disp8
 7561     }
 7562 $populate-mu-type-sizes:end:
 7563     # . epilogue
 7564     89/<- %esp 5/r32/ebp
 7565     5d/pop-to-ebp
 7566     c3/return
 7567 
 7568 # compute sizes of all fields, recursing as necessary
 7569 # sum up all their sizes to arrive at total size
 7570 # fields may be out of order, but that doesn't affect the answer
 7571 populate-mu-type-sizes-in-type:  # T: (addr typeinfo)
 7572     # . prologue
 7573     55/push-ebp
 7574     89/<- %ebp 4/r32/esp
 7575     # . save registers
 7576     50/push-eax
 7577     51/push-ecx
 7578     52/push-edx
 7579     56/push-esi
 7580     57/push-edi
 7581     # esi = T
 7582     8b/-> *(ebp+8) 6/r32/esi
 7583     # if T is already computed, return
 7584     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 7585     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 7586     # if T is being computed, abort
 7587     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7588     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
 7589     # tag T (-2 to -1) to avoid infinite recursion
 7590     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7591     # var total-size/edi: int = 0
 7592     bf/copy-to-edi 0/imm32
 7593     # - for every field, if it's a user-defined type, compute its size
 7594     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 7595     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 7596     89/<- %ecx 0/r32/eax
 7597     # var table-size/edx: int = table->write
 7598     8b/-> *ecx 2/r32/edx  # stream-write
 7599     # var curr/ecx: (addr table_row) = table->data
 7600     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7601     # var max/edx: (addr table_row) = table->data + table->write
 7602     8d/copy-address *(ecx+edx) 2/r32/edx
 7603     {
 7604 $populate-mu-type-sizes-in-type:loop:
 7605       # if (curr >= max) break
 7606       39/compare %ecx 2/r32/edx
 7607       73/jump-if-addr>= break/disp8
 7608       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
 7609       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7610       # compute size of t->input-var
 7611       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7612       (compute-size-of-var %eax)  # => eax
 7613       # result += eax
 7614       01/add-to %edi 0/r32/eax
 7615       # curr += row-size
 7616       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 7617       #
 7618       eb/jump loop/disp8
 7619     }
 7620     # - save result
 7621     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
 7622 $populate-mu-type-sizes-in-type:end:
 7623     # . restore registers
 7624     5f/pop-to-edi
 7625     5e/pop-to-esi
 7626     5a/pop-to-edx
 7627     59/pop-to-ecx
 7628     58/pop-to-eax
 7629     # . epilogue
 7630     89/<- %esp 5/r32/ebp
 7631     5d/pop-to-ebp
 7632     c3/return
 7633 
 7634 $populate-mu-type-sizes-in-type:abort:
 7635     (write-buffered Stderr "cycle in type definitions\n")
 7636     (flush Stderr)
 7637     # . syscall(exit, 1)
 7638     bb/copy-to-ebx  1/imm32
 7639     b8/copy-to-eax  1/imm32/exit
 7640     cd/syscall  0x80/imm8
 7641     # never gets here
 7642 
 7643 # Analogous to size-of, except we need to compute what size-of can just read
 7644 # off the right data structures.
 7645 compute-size-of-var:  # in: (addr var) -> result/eax: int
 7646     # . prologue
 7647     55/push-ebp
 7648     89/<- %ebp 4/r32/esp
 7649     # . push registers
 7650     51/push-ecx
 7651     # var t/ecx: (addr tree type-id) = lookup(v->type)
 7652     8b/-> *(ebp+8) 1/r32/ecx
 7653     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7654     89/<- %ecx 0/r32/eax
 7655     # if (t->is-atom == false) t = lookup(t->left)
 7656     {
 7657       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7658       75/jump-if-!= break/disp8
 7659       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7660       89/<- %ecx 0/r32/eax
 7661     }
 7662     # TODO: ensure t is an atom
 7663     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
 7664 $compute-size-of-var:end:
 7665     # . restore registers
 7666     59/pop-to-ecx
 7667     # . epilogue
 7668     89/<- %esp 5/r32/ebp
 7669     5d/pop-to-ebp
 7670     c3/return
 7671 
 7672 compute-size-of-type-id:  # t: type-id -> result/eax: int
 7673     # . prologue
 7674     55/push-ebp
 7675     89/<- %ebp 4/r32/esp
 7676     # . save registers
 7677     51/push-ecx
 7678     # var out/ecx: (handle typeinfo)
 7679     68/push 0/imm32
 7680     68/push 0/imm32
 7681     89/<- %ecx 4/r32/esp
 7682     # eax = t
 7683     8b/-> *(ebp+8) 0/r32/eax
 7684     # if v is a literal, return 0
 7685     3d/compare-eax-and 0/imm32
 7686     74/jump-if-= $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
 7687     # if v has a user-defined type, compute its size
 7688     # TODO: support non-atom type
 7689     (find-typeinfo %eax %ecx)
 7690     {
 7691       81 7/subop/compare *ecx 0/imm32
 7692       74/jump-if-= break/disp8
 7693 $compute-size-of-type-id:user-defined:
 7694       (populate-mu-type-sizes %eax)
 7695       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 7696       eb/jump $compute-size-of-type-id:end/disp8
 7697     }
 7698     # otherwise return the word size
 7699     b8/copy-to-eax 4/imm32
 7700 $compute-size-of-type-id:end:
 7701     # . reclaim locals
 7702     81 0/subop/add %esp 8/imm32
 7703     # . restore registers
 7704     59/pop-to-ecx
 7705     # . epilogue
 7706     89/<- %esp 5/r32/ebp
 7707     5d/pop-to-ebp
 7708     c3/return
 7709 
 7710 # at this point we have total sizes for all user-defined types
 7711 # compute offsets for each element
 7712 # complication: fields may be out of order
 7713 populate-mu-type-offsets:  # in: (addr typeinfo)
 7714     # . prologue
 7715     55/push-ebp
 7716     89/<- %ebp 4/r32/esp
 7717     # . save registers
 7718     50/push-eax
 7719     51/push-ecx
 7720     52/push-edx
 7721     53/push-ebx
 7722     56/push-esi
 7723     57/push-edi
 7724 #?     (dump-typeinfos "aaa\n")
 7725     # var curr-offset/edi: int = 0
 7726     bf/copy-to-edi 0/imm32
 7727     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
 7728     8b/-> *(ebp+8) 1/r32/ecx
 7729     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
 7730     89/<- %ecx 0/r32/eax
 7731     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
 7732     8b/-> *ecx 2/r32/edx  # stream-write
 7733     c1 5/subop/shift-right-logical  %edx 4/imm8
 7734     # var i/ebx: int = 0
 7735     bb/copy-to-ebx 0/imm32
 7736     {
 7737 $populate-mu-type-offsets:loop:
 7738       39/compare %ebx 2/r32/edx
 7739       7d/jump-if->= break/disp8
 7740 #?       (write-buffered Stderr "looking up index ")
 7741 #?       (print-int32-buffered Stderr %ebx)
 7742 #?       (write-buffered Stderr " in ")
 7743 #?       (print-int32-buffered Stderr *(ebp+8))
 7744 #?       (write-buffered Stderr Newline)
 7745 #?       (flush Stderr)
 7746       # var v/esi: (addr typeinfo-entry)
 7747       (locate-typeinfo-entry-with-index %ecx %ebx)  # => eax
 7748       89/<- %esi 0/r32/eax
 7749       # v->output-var->offset = curr-offset
 7750       # . eax: (addr var)
 7751       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
 7752       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
 7753       # curr-offset += size-of(v->input-var)
 7754       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7755       (size-of %eax)  # => eax
 7756       01/add-to %edi 0/r32/eax
 7757       # ++i
 7758       43/increment-ebx
 7759       eb/jump loop/disp8
 7760     }
 7761 $populate-mu-type-offsets:end:
 7762     # . restore registers
 7763     5f/pop-to-edi
 7764     5e/pop-to-esi
 7765     5b/pop-to-ebx
 7766     5a/pop-to-edx
 7767     59/pop-to-ecx
 7768     58/pop-to-eax
 7769     # . epilogue
 7770     89/<- %esp 5/r32/ebp
 7771     5d/pop-to-ebp
 7772     c3/return
 7773 
 7774 locate-typeinfo-entry-with-index:  # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int -> result/eax: (addr typeinfo-entry)
 7775     # . prologue
 7776     55/push-ebp
 7777     89/<- %ebp 4/r32/esp
 7778     # . save registers
 7779     51/push-ecx
 7780     52/push-edx
 7781     53/push-ebx
 7782     56/push-esi
 7783     57/push-edi
 7784     # esi = table
 7785     8b/-> *(ebp+8) 6/r32/esi
 7786     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
 7787     8d/copy-address *(esi+0xc) 1/r32/ecx
 7788     # var max/edx: (addr byte) = &table->data[table->write]
 7789     8b/-> *esi 2/r32/edx
 7790     8d/copy-address *(ecx+edx) 2/r32/edx
 7791     {
 7792 $locate-typeinfo-entry-with-index:loop:
 7793       39/compare %ecx 2/r32/edx
 7794       73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8
 7795       # var v/eax: (addr typeinfo-entry)
 7796       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7797       # if (v->index == idx) return v
 7798       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
 7799 #?       (write-buffered Stderr "comparing ")
 7800 #?       (print-int32-buffered Stderr %ebx)
 7801 #?       (write-buffered Stderr " and ")
 7802 #?       (print-int32-buffered Stderr *(ebp+0xc))
 7803 #?       (write-buffered Stderr Newline)
 7804 #?       (flush Stderr)
 7805       39/compare *(ebp+0xc) 3/r32/ebx
 7806       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
 7807       # curr += Typeinfo-entry-size
 7808       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
 7809       #
 7810       eb/jump loop/disp8
 7811     }
 7812     # return 0
 7813     b8/copy-to-eax 0/imm32
 7814 $locate-typeinfo-entry-with-index:end:
 7815 #?     (write-buffered Stderr "returning ")
 7816 #?     (print-int32-buffered Stderr %eax)
 7817 #?     (write-buffered Stderr Newline)
 7818 #?     (flush Stderr)
 7819     # . restore registers
 7820     5f/pop-to-edi
 7821     5e/pop-to-esi
 7822     5b/pop-to-ebx
 7823     5a/pop-to-edx
 7824     59/pop-to-ecx
 7825     # . epilogue
 7826     89/<- %esp 5/r32/ebp
 7827     5d/pop-to-ebp
 7828     c3/return
 7829 
 7830 $locate-typeinfo-entry-with-index:abort:
 7831     (write-buffered Stderr "overflowing typeinfo-entry->index ")
 7832     (print-int32-buffered Stderr %ecx)
 7833     (write-buffered Stderr "\n")
 7834     (flush Stderr)
 7835     # . syscall(exit, 1)
 7836     bb/copy-to-ebx  1/imm32
 7837     b8/copy-to-eax  1/imm32/exit
 7838     cd/syscall  0x80/imm8
 7839     # never gets here
 7840 
 7841 dump-typeinfos:  # hdr: (addr array byte)
 7842     # . prologue
 7843     55/push-ebp
 7844     89/<- %ebp 4/r32/esp
 7845     # . save registers
 7846     50/push-eax
 7847     #
 7848     (write-buffered Stderr *(ebp+8))
 7849     (flush Stderr)
 7850     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 7851     (lookup *_Program-types *_Program-types->payload)  # => eax
 7852     {
 7853       # if (curr == null) break
 7854       3d/compare-eax-and 0/imm32
 7855       74/jump-if-= break/disp8
 7856       (write-buffered Stderr "---\n")
 7857       (flush Stderr)
 7858       (dump-typeinfo %eax)
 7859       # curr = lookup(curr->next)
 7860       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7861       eb/jump loop/disp8
 7862     }
 7863 $dump-typeinfos:end:
 7864     # . restore registers
 7865     58/pop-to-eax
 7866     # . epilogue
 7867     89/<- %esp 5/r32/ebp
 7868     5d/pop-to-ebp
 7869     c3/return
 7870 
 7871 dump-typeinfo:  # in: (addr typeinfo)
 7872     # . prologue
 7873     55/push-ebp
 7874     89/<- %ebp 4/r32/esp
 7875     # . save registers
 7876     50/push-eax
 7877     51/push-ecx
 7878     52/push-edx
 7879     53/push-ebx
 7880     56/push-esi
 7881     57/push-edi
 7882     # esi = in
 7883     8b/-> *(ebp+8) 6/r32/esi
 7884     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 7885     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 7886     89/<- %ecx 0/r32/eax
 7887     (write-buffered Stderr "id:")
 7888     (print-int32-buffered Stderr *esi)
 7889     (write-buffered Stderr "\n")
 7890     (write-buffered Stderr "fields @ ")
 7891     (print-int32-buffered Stderr %ecx)
 7892     (write-buffered Stderr Newline)
 7893     (flush Stderr)
 7894     (write-buffered Stderr "  write: ")
 7895     (print-int32-buffered Stderr *ecx)
 7896     (write-buffered Stderr Newline)
 7897     (flush Stderr)
 7898     (write-buffered Stderr "  read: ")
 7899     (print-int32-buffered Stderr *(ecx+4))
 7900     (write-buffered Stderr Newline)
 7901     (flush Stderr)
 7902     (write-buffered Stderr "  size: ")
 7903     (print-int32-buffered Stderr *(ecx+8))
 7904     (write-buffered Stderr Newline)
 7905     (flush Stderr)
 7906     # var table-size/edx: int = table->write
 7907     8b/-> *ecx 2/r32/edx  # stream-write
 7908     # var curr/ecx: (addr table_row) = table->data
 7909     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7910     # var max/edx: (addr table_row) = table->data + table->write
 7911     8d/copy-address *(ecx+edx) 2/r32/edx
 7912     {
 7913 $dump-typeinfo:loop:
 7914       # if (curr >= max) break
 7915       39/compare %ecx 2/r32/edx
 7916       0f 83/jump-if-addr>= break/disp32
 7917       (write-buffered Stderr "  row:\n")
 7918       (write-buffered Stderr "    key: ")
 7919       (print-int32-buffered Stderr *ecx)
 7920       (write-buffered Stderr ",")
 7921       (print-int32-buffered Stderr *(ecx+4))
 7922       (write-buffered Stderr " = '")
 7923       (lookup *ecx *(ecx+4))
 7924       (write-buffered Stderr %eax)
 7925       (write-buffered Stderr "' @ ")
 7926       (print-int32-buffered Stderr %eax)
 7927       (write-buffered Stderr Newline)
 7928       (flush Stderr)
 7929       (write-buffered Stderr "    value: ")
 7930       (print-int32-buffered Stderr *(ecx+8))
 7931       (write-buffered Stderr ",")
 7932       (print-int32-buffered Stderr *(ecx+0xc))
 7933       (write-buffered Stderr " = typeinfo-entry@")
 7934       (lookup *(ecx+8) *(ecx+0xc))
 7935       (print-int32-buffered Stderr %eax)
 7936       (write-buffered Stderr Newline)
 7937       (flush Stderr)
 7938       (write-buffered Stderr "        input var@")
 7939       (print-int32-buffered Stderr *eax)
 7940       (write-buffered Stderr ",")
 7941       (print-int32-buffered Stderr *(eax+4))
 7942       (write-buffered Stderr "->")
 7943       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var
 7944       (print-int32-buffered Stderr %eax)
 7945       {
 7946         3d/compare-eax-and 0/imm32
 7947         74/jump-if-= break/disp8
 7948         (write-buffered Stderr " ")
 7949         # TODO
 7950       }
 7951       (write-buffered Stderr Newline)
 7952       (flush Stderr)
 7953       (lookup *(ecx+8) *(ecx+0xc))
 7954       (write-buffered Stderr "        index: ")
 7955       (print-int32-buffered Stderr *(eax+8))
 7956       (write-buffered Stderr Newline)
 7957       (flush Stderr)
 7958       (write-buffered Stderr "        output var@")
 7959       (print-int32-buffered Stderr *(eax+0xc))
 7960       (write-buffered Stderr ",")
 7961       (print-int32-buffered Stderr *(eax+0x10))
 7962       (write-buffered Stderr "->")
 7963       (lookup *(eax+0xc) *(eax+0x10))  # Typeinfo-entry-output-var
 7964       (print-int32-buffered Stderr %eax)
 7965       (write-buffered Stderr Newline)
 7966       (flush Stderr)
 7967       {
 7968         3d/compare-eax-and 0/imm32
 7969         0f 84/jump-if-= break/disp32
 7970         (write-buffered Stderr "          name: ")
 7971         89/<- %ebx 0/r32/eax
 7972         (print-int32-buffered Stderr *ebx)  # Var-name
 7973         (write-buffered Stderr ",")
 7974         (print-int32-buffered Stderr *(ebx+4))  # Var-name
 7975         (write-buffered Stderr "->")
 7976         (lookup *ebx *(ebx+4))  # Var-name
 7977         (print-int32-buffered Stderr %eax)
 7978         {
 7979           3d/compare-eax-and 0/imm32
 7980           74/jump-if-= break/disp8
 7981           (write-buffered Stderr Space)
 7982           (write-buffered Stderr %eax)
 7983         }
 7984         (write-buffered Stderr Newline)
 7985         (flush Stderr)
 7986         (write-buffered Stderr "          block depth: ")
 7987         (print-int32-buffered Stderr *(ebx+0x10))  # Var-block-depth
 7988         (write-buffered Stderr Newline)
 7989         (flush Stderr)
 7990         (write-buffered Stderr "          stack offset: ")
 7991         (print-int32-buffered Stderr *(ebx+0x14))  # Var-offset
 7992         (write-buffered Stderr Newline)
 7993         (flush Stderr)
 7994         (write-buffered Stderr "          reg: ")
 7995         (print-int32-buffered Stderr *(ebx+0x18))  # Var-register
 7996         (write-buffered Stderr ",")
 7997         (print-int32-buffered Stderr *(ebx+0x1c))  # Var-register
 7998         (write-buffered Stderr "->")
 7999         (flush Stderr)
 8000         (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
 8001         (print-int32-buffered Stderr %eax)
 8002         {
 8003           3d/compare-eax-and 0/imm32
 8004           74/jump-if-= break/disp8
 8005           (write-buffered Stderr Space)
 8006           (write-buffered Stderr %eax)
 8007         }
 8008         (write-buffered Stderr Newline)
 8009         (flush Stderr)
 8010       }
 8011       (flush Stderr)
 8012       # curr += row-size
 8013       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 8014       #
 8015       e9/jump loop/disp32
 8016     }
 8017 $dump-typeinfo:end:
 8018     # . restore registers
 8019     5f/pop-to-edi
 8020     5e/pop-to-esi
 8021     5b/pop-to-ebx
 8022     5a/pop-to-edx
 8023     59/pop-to-ecx
 8024     58/pop-to-eax
 8025     # . epilogue
 8026     89/<- %esp 5/r32/ebp
 8027     5d/pop-to-ebp
 8028     c3/return
 8029 
 8030 #######################################################
 8031 # Type-checking
 8032 #######################################################
 8033 
 8034 check-mu-types:
 8035     # . prologue
 8036     55/push-ebp
 8037     89/<- %ebp 4/r32/esp
 8038     #
 8039 $check-mu-types:end:
 8040     # . epilogue
 8041     89/<- %esp 5/r32/ebp
 8042     5d/pop-to-ebp
 8043     c3/return
 8044 
 8045 size-of:  # v: (addr var) -> result/eax: int
 8046     # . prologue
 8047     55/push-ebp
 8048     89/<- %ebp 4/r32/esp
 8049     # . save registers
 8050     51/push-ecx
 8051     # var t/ecx: (addr tree type-id) = lookup(v->type)
 8052     8b/-> *(ebp+8) 1/r32/ecx
 8053 #?     (write-buffered Stderr "size-of ")
 8054 #?     (print-int32-buffered Stderr %ecx)
 8055 #?     (write-buffered Stderr Newline)
 8056 #?     (write-buffered Stderr "type allocid: ")
 8057 #?     (print-int32-buffered Stderr *(ecx+8))
 8058 #?     (write-buffered Stderr Newline)
 8059 #?     (flush Stderr)
 8060     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8061     89/<- %ecx 0/r32/eax
 8062     # if is-mu-array?(t) return size-of-array(t)
 8063     {
 8064       (is-mu-array? %ecx)  # => eax
 8065       3d/compare-eax-and 0/imm32/false
 8066       74/jump-if-= break/disp8
 8067       (size-of-array %ecx)  # => eax
 8068       eb/jump $size-of:end/disp8
 8069     }
 8070     # if (!t->is-atom?) t = lookup(t->left)
 8071     {
 8072       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8073       75/jump-if-!= break/disp8
 8074       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8075       89/<- %ecx 0/r32/eax
 8076     }
 8077     # TODO: assert t->is-atom?
 8078     (size-of-type-id *(ecx+4))  # Tree-value => eax
 8079 $size-of:end:
 8080     # . restore registers
 8081     59/pop-to-ecx
 8082     # . epilogue
 8083     89/<- %esp 5/r32/ebp
 8084     5d/pop-to-ebp
 8085     c3/return
 8086 
 8087 size-of-deref:  # v: (addr var) -> result/eax: int
 8088     # . prologue
 8089     55/push-ebp
 8090     89/<- %ebp 4/r32/esp
 8091     # . save registers
 8092     51/push-ecx
 8093     # var t/ecx: (addr tree type-id) = lookup(v->type)
 8094     8b/-> *(ebp+8) 1/r32/ecx
 8095     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8096     89/<- %ecx 0/r32/eax
 8097     # TODO: assert(t is an addr)
 8098     # t = lookup(t->right)
 8099     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8100     89/<- %ecx 0/r32/eax
 8101     # if is-mu-array?(t) return size-of-array(t)
 8102     {
 8103       (is-mu-array? %ecx)  # => eax
 8104       3d/compare-eax-and 0/imm32/false
 8105       74/jump-if-= break/disp8
 8106       (size-of-array %ecx)  # => eax
 8107       eb/jump $size-of:end/disp8
 8108     }
 8109     # if (!t->is-atom?) t = lookup(t->left)
 8110     {
 8111       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8112       75/jump-if-!= break/disp8
 8113       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8114       89/<- %ecx 0/r32/eax
 8115     }
 8116     # TODO: assert t->is-atom?
 8117     (size-of-type-id *(ecx+4))  # Tree-value => eax
 8118 $size-of-deref:end:
 8119     # . restore registers
 8120     59/pop-to-ecx
 8121     # . epilogue
 8122     89/<- %esp 5/r32/ebp
 8123     5d/pop-to-ebp
 8124     c3/return
 8125 
 8126 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
 8127     # . prologue
 8128     55/push-ebp
 8129     89/<- %ebp 4/r32/esp
 8130     # . save registers
 8131     51/push-ecx
 8132     # ecx = t
 8133     8b/-> *(ebp+8) 1/r32/ecx
 8134     # if t->is-atom?, return false
 8135     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8136     75/jump-if-!= $is-mu-array?:return-false/disp8
 8137     # if !t->left->is-atom?, return false
 8138     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8139     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 8140     74/jump-if-= $is-mu-array?:return-false/disp8
 8141     # return t->left->value == array
 8142     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
 8143     0f 94/set-if-= %al
 8144     81 4/subop/and %eax 0xff/imm32
 8145     eb/jump $is-mu-array?:end/disp8
 8146 $is-mu-array?:return-false:
 8147     b8/copy-to-eax 0/imm32/false
 8148 $is-mu-array?:end:
 8149     # . restore registers
 8150     59/pop-to-ecx
 8151     # . epilogue
 8152     89/<- %esp 5/r32/ebp
 8153     5d/pop-to-ebp
 8154     c3/return
 8155 
 8156 size-of-array:  # a: (addr tree type-id) -> result/eax: int
 8157     # . prologue
 8158     55/push-ebp
 8159     89/<- %ebp 4/r32/esp
 8160     # . save registers
 8161     51/push-ecx
 8162     52/push-edx
 8163     #
 8164     8b/-> *(ebp+8) 1/r32/ecx
 8165     # TODO: assert that a->left is 'array'
 8166     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8167     89/<- %ecx 0/r32/eax
 8168     # var elem-type/edx: type-id = a->right->left->value
 8169     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8170     8b/-> *(eax+4) 2/r32/edx  # Tree-value
 8171     # var array-size/ecx: int = a->right->right->left->value
 8172     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8173     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 8174     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
 8175     # return array-size * size-of(elem-type)
 8176     (size-of-type-id %edx)  # => eax
 8177     f7 4/subop/multiply-into-eax %ecx
 8178     05/add-to-eax 4/imm32  # for array size
 8179 $size-of-array:end:
 8180     # . restore registers
 8181     5a/pop-to-edx
 8182     59/pop-to-ecx
 8183     # . epilogue
 8184     89/<- %esp 5/r32/ebp
 8185     5d/pop-to-ebp
 8186     c3/return
 8187 
 8188 size-of-type-id:  # t: type-id -> result/eax: int
 8189     # . prologue
 8190     55/push-ebp
 8191     89/<- %ebp 4/r32/esp
 8192     # . save registers
 8193     51/push-ecx
 8194     # var out/ecx: (handle typeinfo)
 8195     68/push 0/imm32
 8196     68/push 0/imm32
 8197     89/<- %ecx 4/r32/esp
 8198     # eax = t
 8199     8b/-> *(ebp+8) 0/r32/eax
 8200     # if t is a literal, return 0
 8201     3d/compare-eax-and 0/imm32
 8202     74/jump-if-= $size-of-type-id:end/disp8  # eax changes type from type-id to int
 8203     # if t is a handle, return 8
 8204     3d/compare-eax-and 4/imm32/handle
 8205     {
 8206       75/jump-if-!= break/disp8
 8207       b8/copy-to-eax 8/imm32
 8208       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
 8209     }
 8210     # if t is a user-defined type, return its size
 8211     # TODO: support non-atom type
 8212     (find-typeinfo %eax %ecx)
 8213     {
 8214       81 7/subop/compare *ecx 0/imm32
 8215       74/jump-if-= break/disp8
 8216 $size-of-type-id:user-defined:
 8217       (lookup *ecx *(ecx+4))  # => eax
 8218       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 8219       eb/jump $size-of-type-id:end/disp8
 8220     }
 8221     # otherwise return the word size
 8222     b8/copy-to-eax 4/imm32
 8223 $size-of-type-id:end:
 8224     # . reclaim locals
 8225     81 0/subop/add %esp 8/imm32
 8226     # . restore registers
 8227     59/pop-to-ecx
 8228     # . epilogue
 8229     89/<- %esp 5/r32/ebp
 8230     5d/pop-to-ebp
 8231     c3/return
 8232 
 8233 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
 8234     # . prologue
 8235     55/push-ebp
 8236     89/<- %ebp 4/r32/esp
 8237     # . save registers
 8238     51/push-ecx
 8239     52/push-edx
 8240     # ecx = a
 8241     8b/-> *(ebp+8) 1/r32/ecx
 8242     # edx = b
 8243     8b/-> *(ebp+0xc) 2/r32/edx
 8244     # if (a == b) return true
 8245     8b/-> %ecx 0/r32/eax  # Var-type
 8246     39/compare %edx 0/r32/eax  # Var-type
 8247     b8/copy-to-eax 1/imm32/true
 8248     74/jump-if-= $type-equal?:end/disp8
 8249     # if (a < MAX_TYPE_ID) return false
 8250     81 7/subop/compare %ecx 0x10000/imm32
 8251     b8/copy-to-eax 0/imm32/false
 8252     72/jump-if-addr< $type-equal?:end/disp8
 8253     # if (b < MAX_TYPE_ID) return false
 8254     81 7/subop/compare %edx 0x10000/imm32
 8255     b8/copy-to-eax 0/imm32/false
 8256     72/jump-if-addr< $type-equal?:end/disp8
 8257     # if (!type-equal?(a->left, b->left)) return false
 8258     (type-equal? *(ecx+4) *(edx+4))  # Tree-left, Tree-left => eax
 8259     3d/compare-eax-and 0/imm32/false
 8260     74/jump-if-= $type-equal?:end/disp8
 8261     # return type-equal?(a->right, b->right)
 8262     (type-equal? *(ecx+8) *(edx+8))  # Tree-right, Tree-right => eax
 8263 $type-equal?:end:
 8264     # . restore registers
 8265     5a/pop-to-edx
 8266     59/pop-to-ecx
 8267     # . epilogue
 8268     89/<- %esp 5/r32/ebp
 8269     5d/pop-to-ebp
 8270     c3/return
 8271 
 8272 #######################################################
 8273 # Code-generation
 8274 #######################################################
 8275 
 8276 == data
 8277 
 8278 Curr-block-depth:  # (addr int)
 8279     0/imm32
 8280 Curr-local-stack-offset:  # (addr int)
 8281     0/imm32
 8282 
 8283 == code
 8284 
 8285 emit-subx:  # out: (addr buffered-file)
 8286     # . prologue
 8287     55/push-ebp
 8288     89/<- %ebp 4/r32/esp
 8289     # . save registers
 8290     50/push-eax
 8291     # var curr/eax: (addr function) = *Program->functions
 8292     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 8293     {
 8294       # if (curr == null) break
 8295       3d/compare-eax-and 0/imm32
 8296       0f 84/jump-if-= break/disp32
 8297       (emit-subx-function *(ebp+8) %eax)
 8298       # curr = lookup(curr->next)
 8299       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 8300       e9/jump loop/disp32
 8301     }
 8302 $emit-subx:end:
 8303     # . restore registers
 8304     58/pop-to-eax
 8305     # . epilogue
 8306     89/<- %esp 5/r32/ebp
 8307     5d/pop-to-ebp
 8308     c3/return
 8309 
 8310 emit-subx-function:  # out: (addr buffered-file), f: (addr function)
 8311     # . prologue
 8312     55/push-ebp
 8313     89/<- %ebp 4/r32/esp
 8314     # some preprocessing
 8315     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
 8316     # . save registers
 8317     50/push-eax
 8318     51/push-ecx
 8319     52/push-edx
 8320     57/push-edi
 8321     # initialize some global state
 8322     c7 0/subop/copy *Curr-block-depth 1/imm32
 8323     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
 8324     # ecx = f
 8325     8b/-> *(ebp+0xc) 1/r32/ecx
 8326     # var vars/edx: (stack (addr var) 256)
 8327     81 5/subop/subtract %esp 0xc00/imm32
 8328     68/push 0xc00/imm32/size
 8329     68/push 0/imm32/top
 8330     89/<- %edx 4/r32/esp
 8331     # var name/eax: (addr array byte) = lookup(f->name)
 8332     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8333     #
 8334     (write-buffered *(ebp+8) %eax)
 8335     (write-buffered *(ebp+8) ":\n")
 8336     (emit-subx-prologue *(ebp+8))
 8337     # var outputs/edi: (addr list var) = lookup(f->outputs)
 8338     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8339     89/<- %edi 0/r32/eax
 8340     # var body/eax: (addr block) = lookup(f->body)
 8341     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
 8342     #
 8343     (emit-subx-block *(ebp+8) %eax %edx %edi)
 8344     (emit-subx-epilogue *(ebp+8))
 8345     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
 8346     # been cleaned up
 8347 $emit-subx-function:end:
 8348     # . reclaim locals
 8349     81 0/subop/add %esp 0xc08/imm32
 8350     # . restore registers
 8351     5f/pop-to-edi
 8352     5a/pop-to-edx
 8353     59/pop-to-ecx
 8354     58/pop-to-eax
 8355     # . epilogue
 8356     89/<- %esp 5/r32/ebp
 8357     5d/pop-to-ebp
 8358     c3/return
 8359 
 8360 populate-mu-type-offsets-in-inouts:  # f: (addr function)
 8361     # . prologue
 8362     55/push-ebp
 8363     89/<- %ebp 4/r32/esp
 8364     # . save registers
 8365     50/push-eax
 8366     51/push-ecx
 8367     52/push-edx
 8368     53/push-ebx
 8369     57/push-edi
 8370     # var next-offset/edx: int = 8
 8371     ba/copy-to-edx 8/imm32
 8372     # var curr/ecx: (addr list var) = lookup(f->inouts)
 8373     8b/-> *(ebp+8) 1/r32/ecx
 8374     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8375     89/<- %ecx 0/r32/eax
 8376     {
 8377 $populate-mu-type-offsets-in-inouts:loop:
 8378       81 7/subop/compare %ecx 0/imm32
 8379       74/jump-if-= break/disp8
 8380       # var v/ebx: (addr var) = lookup(curr->value)
 8381       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 8382       89/<- %ebx 0/r32/eax
 8383 #?       (lookup *ebx *(ebx+4))
 8384 #?       (write-buffered Stderr "setting offset of fn inout ")
 8385 #?       (write-buffered Stderr %eax)
 8386 #?       (write-buffered Stderr "@")
 8387 #?       (print-int32-buffered Stderr %ebx)
 8388 #?       (write-buffered Stderr " to ")
 8389 #?       (print-int32-buffered Stderr %edx)
 8390 #?       (write-buffered Stderr Newline)
 8391 #?       (flush Stderr)
 8392       # v->offset = next-offset
 8393       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
 8394       # next-offset += size-of(v)
 8395       (size-of %ebx)  # => eax
 8396       01/add-to %edx 0/r32/eax
 8397       # curr = lookup(curr->next)
 8398       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 8399       89/<- %ecx 0/r32/eax
 8400       #
 8401       eb/jump loop/disp8
 8402     }
 8403 $populate-mu-type-offsets-in-inouts:end:
 8404     # . restore registers
 8405     5f/pop-to-edi
 8406     5b/pop-to-ebx
 8407     5a/pop-to-edx
 8408     59/pop-to-ecx
 8409     58/pop-to-eax
 8410     # . epilogue
 8411     89/<- %esp 5/r32/ebp
 8412     5d/pop-to-ebp
 8413     c3/return
 8414 
 8415 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn-outputs: (addr list var)
 8416     # . prologue
 8417     55/push-ebp
 8418     89/<- %ebp 4/r32/esp
 8419     # . save registers
 8420     50/push-eax
 8421     51/push-ecx
 8422     53/push-ebx
 8423     56/push-esi
 8424     # esi = stmts
 8425     8b/-> *(ebp+0xc) 6/r32/esi
 8426     #
 8427     {
 8428 $emit-subx-stmt-list:loop:
 8429       81 7/subop/compare %esi 0/imm32
 8430       0f 84/jump-if-= break/disp32
 8431       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
 8432       (lookup *esi *(esi+4))  # List-value List-value => eax
 8433       89/<- %ecx 0/r32/eax
 8434       {
 8435 $emit-subx-stmt-list:check-for-block:
 8436         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 8437         75/jump-if-!= break/disp8
 8438 $emit-subx-stmt-list:block:
 8439         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14))
 8440       }
 8441       {
 8442 $emit-subx-stmt-list:check-for-stmt:
 8443         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 8444         0f 85/jump-if-!= break/disp32
 8445 $emit-subx-stmt-list:stmt1:
 8446         {
 8447           (is-mu-branch? %ecx)  # => eax
 8448           3d/compare-eax-and 0/imm32/false
 8449           0f 84/jump-if-= break/disp32
 8450 $emit-subx-stmt-list:branch-stmt:
 8451 +-- 27 lines: # unconditional loops ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 8478 +-- 16 lines: # unconditional breaks ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 8494 +-- 38 lines: # simple conditional branches without a target ---------------------------------------------------------------------------------------------------------------------------------------------------
 8532 +-- 19 lines: # conditional branches with an explicit target ---------------------------------------------------------------------------------------------------------------------------------------------------
 8551         }
 8552 $emit-subx-stmt-list:1-to-1:
 8553         (emit-subx-stmt *(ebp+8) %ecx Primitives)
 8554         e9/jump $emit-subx-stmt-list:continue/disp32
 8555       }
 8556       {
 8557 $emit-subx-stmt-list:check-for-var-def:
 8558         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
 8559         75/jump-if-!= break/disp8
 8560 $emit-subx-stmt-list:var-def:
 8561         (emit-subx-var-def *(ebp+8) %ecx)
 8562         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
 8563         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
 8564         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
 8565         #
 8566         eb/jump $emit-subx-stmt-list:continue/disp8
 8567       }
 8568       {
 8569 $emit-subx-stmt-list:check-for-reg-var-def:
 8570         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
 8571         0f 85/jump-if-!= break/disp32
 8572 $emit-subx-stmt-list:reg-var-def:
 8573         # TODO: ensure that there's exactly one output
 8574         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14))
 8575         # emit the instruction as usual
 8576         (emit-subx-stmt *(ebp+8) %ecx Primitives)
 8577         #
 8578         eb/jump $emit-subx-stmt-list:continue/disp8
 8579       }
 8580 $emit-subx-stmt-list:continue:
 8581       # TODO: raise an error on unrecognized Stmt-tag
 8582       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
 8583       89/<- %esi 0/r32/eax
 8584       e9/jump loop/disp32
 8585     }
 8586 $emit-subx-stmt-list:emit-cleanup:
 8587     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
 8588 $emit-subx-stmt-list:clean-up:
 8589     (clean-up-blocks *(ebp+0x10) *Curr-block-depth)
 8590 $emit-subx-stmt-list:end:
 8591     # . restore registers
 8592     5e/pop-to-esi
 8593     5b/pop-to-ebx
 8594     59/pop-to-ecx
 8595     58/pop-to-eax
 8596     # . epilogue
 8597     89/<- %esp 5/r32/ebp
 8598     5d/pop-to-ebp
 8599     c3/return
 8600 
 8601 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
 8602 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)
 8603     # . prologue
 8604     55/push-ebp
 8605     89/<- %ebp 4/r32/esp
 8606     # . save registers
 8607     50/push-eax
 8608     51/push-ecx
 8609     52/push-edx
 8610     # ecx = stmt
 8611     8b/-> *(ebp+0xc) 1/r32/ecx
 8612     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
 8613     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8614     # TODO: assert !sv->is-deref?
 8615     # var v/ecx: (addr var) = lookup(sv->value)
 8616     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8617     89/<- %ecx 0/r32/eax
 8618     # v->block-depth = *Curr-block-depth
 8619     8b/-> *Curr-block-depth 0/r32/eax
 8620     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8621 #?     (write-buffered Stderr "var ")
 8622 #?     (lookup *ecx *(ecx+4))
 8623 #?     (write-buffered Stderr %eax)
 8624 #?     (write-buffered Stderr " at depth ")
 8625 #?     (print-int32-buffered Stderr *(ecx+0x10))
 8626 #?     (write-buffered Stderr Newline)
 8627 #?     (flush Stderr)
 8628     # ensure that v is in a register
 8629     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 8630     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
 8631     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn-outputs)
 8632     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
 8633     89/<- %edx 0/r32/eax
 8634     3d/compare-eax-and 0/imm32/false
 8635     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
 8636     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
 8637     89/<- %edx 0/r32/eax
 8638     # check emit-spill?
 8639     3d/compare-eax-and 0/imm32/false
 8640     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
 8641     # TODO: assert(size-of(output) == 4)
 8642     # *Curr-local-stack-offset -= 4
 8643     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
 8644     # emit spill
 8645     (emit-indent *(ebp+8) *Curr-block-depth)
 8646     (write-buffered *(ebp+8) "ff 6/subop/push %")
 8647     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8648     (write-buffered *(ebp+8) %eax)
 8649     (write-buffered *(ebp+8) Newline)
 8650 $push-output-and-maybe-emit-spill:push:
 8651     8b/-> *(ebp+0xc) 1/r32/ecx
 8652     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8653     # push(vars, {sv->value, emit-spill?})
 8654     (push *(ebp+0x10) *eax)  # Stmt-var-value
 8655     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
 8656     (push *(ebp+0x10) %edx)
 8657 $push-output-and-maybe-emit-spill:end:
 8658     # . restore registers
 8659     5a/pop-to-edx
 8660     59/pop-to-ecx
 8661     58/pop-to-eax
 8662     # . epilogue
 8663     89/<- %esp 5/r32/ebp
 8664     5d/pop-to-ebp
 8665     c3/return
 8666 
 8667 $push-output-and-maybe-emit-spill:abort:
 8668     # error("var '" var->name "' initialized from an instruction must live in a register\n")
 8669     (write-buffered Stderr "var '")
 8670     (write-buffered Stderr *eax)  # Var-name
 8671     (write-buffered Stderr "' initialized from an instruction must live in a register\n")
 8672     (flush Stderr)
 8673     # . syscall(exit, 1)
 8674     bb/copy-to-ebx  1/imm32
 8675     b8/copy-to-eax  1/imm32/exit
 8676     cd/syscall  0x80/imm8
 8677     # never gets here
 8678 
 8679 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
 8680     # . prologue
 8681     55/push-ebp
 8682     89/<- %ebp 4/r32/esp
 8683     # . save registers
 8684     50/push-eax
 8685     51/push-ecx
 8686     # ecx = stmt
 8687     8b/-> *(ebp+0xc) 1/r32/ecx
 8688     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
 8689     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8690     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8691     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8692     # clean up until target block
 8693     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
 8694     # emit jump to target block
 8695     (emit-indent *(ebp+8) *Curr-block-depth)
 8696     (write-buffered *(ebp+8) "e9/jump ")
 8697     (write-buffered *(ebp+8) %eax)
 8698     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8699     (string-starts-with? %eax "break")
 8700     3d/compare-eax-and 0/imm32/false
 8701     {
 8702       74/jump-if-= break/disp8
 8703       (write-buffered *(ebp+8) ":break/disp32\n")
 8704     }
 8705     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
 8706     {
 8707       75/jump-if-!= break/disp8
 8708       (write-buffered *(ebp+8) ":loop/disp32\n")
 8709     }
 8710 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
 8711     # . restore registers
 8712     59/pop-to-ecx
 8713     58/pop-to-eax
 8714     # . epilogue
 8715     89/<- %esp 5/r32/ebp
 8716     5d/pop-to-ebp
 8717     c3/return
 8718 
 8719 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
 8720     # . prologue
 8721     55/push-ebp
 8722     89/<- %ebp 4/r32/esp
 8723     # . save registers
 8724     51/push-ecx
 8725     # ecx = lookup(stmt->operation)
 8726     8b/-> *(ebp+8) 1/r32/ecx
 8727     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8728     89/<- %ecx 0/r32/eax
 8729     # if (stmt->operation starts with "loop") return true
 8730     (string-starts-with? %ecx "loop")  # => eax
 8731     3d/compare-eax-and 0/imm32/false
 8732     75/jump-if-not-equal $is-mu-branch?:end/disp8
 8733     # otherwise return (stmt->operation starts with "break")
 8734     (string-starts-with? %ecx "break")  # => eax
 8735 $is-mu-branch?:end:
 8736     # . restore registers
 8737     59/pop-to-ecx
 8738     # . epilogue
 8739     89/<- %esp 5/r32/ebp
 8740     5d/pop-to-ebp
 8741     c3/return
 8742 
 8743 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
 8744     # . prologue
 8745     55/push-ebp
 8746     89/<- %ebp 4/r32/esp
 8747     # . save registers
 8748     50/push-eax
 8749     # eax = stmt
 8750     8b/-> *(ebp+0xc) 0/r32/eax
 8751     #
 8752     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
 8753     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
 8754     (emit-indent *(ebp+8) *Curr-block-depth)
 8755     (lookup *eax *(eax+4))  # => eax
 8756     (write-buffered *(ebp+8) %eax)
 8757     (write-buffered *(ebp+8) " break/disp32\n")
 8758 $emit-reverse-break:end:
 8759     # . restore registers
 8760     58/pop-to-eax
 8761     # . epilogue
 8762     89/<- %esp 5/r32/ebp
 8763     5d/pop-to-ebp
 8764     c3/return
 8765 
 8766 == data
 8767 
 8768 # Table from Mu branch instructions to the reverse SubX opcodes for them.
 8769 Reverse-branch:  # (table (handle array byte) (handle array byte))
 8770   # a table is a stream
 8771   0x140/imm32/write
 8772   0/imm32/read
 8773   0x140/imm32/size
 8774   # data
 8775   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8776   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8777   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8778   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8779   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8780   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8781   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8782   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8783   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8784   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8785   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8786   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8787   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8788   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8789   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8790   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8791   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8792   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8793   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8794   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8795 
 8796 == code
 8797 
 8798 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
 8799     # . prologue
 8800     55/push-ebp
 8801     89/<- %ebp 4/r32/esp
 8802     # . save registers
 8803     50/push-eax
 8804     51/push-ecx
 8805     52/push-edx
 8806     53/push-ebx
 8807     56/push-esi
 8808     # ecx = vars
 8809     8b/-> *(ebp+0xc) 1/r32/ecx
 8810     # var eax: int = vars->top
 8811     8b/-> *ecx 0/r32/eax
 8812     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 8813     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
 8814     # var min/ecx: (addr handle var) = vars->data
 8815     8d/copy-address *(ecx+8) 1/r32/ecx
 8816     # edx = depth
 8817     8b/-> *(ebp+0x10) 2/r32/edx
 8818     {
 8819 $emit-unconditional-jump-to-depth:loop:
 8820       # if (curr < min) break
 8821       39/compare %esi 1/r32/ecx
 8822       0f 82/jump-if-addr< break/disp32
 8823       # var v/ebx: (addr var) = lookup(*curr)
 8824       (lookup *esi *(esi+4))  # => eax
 8825       89/<- %ebx 0/r32/eax
 8826       # if (v->block-depth < until-block-depth) break
 8827       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8828       0f 8c/jump-if-< break/disp32
 8829       {
 8830 $emit-unconditional-jump-to-depth:check:
 8831         # if v->block-depth != until-block-depth, continue
 8832         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8833         0f 85/jump-if-!= break/disp32
 8834 $emit-unconditional-jump-to-depth:depth-found:
 8835         # if v is not a literal, continue
 8836         (size-of %ebx)  # => eax
 8837         3d/compare-eax-and 0/imm32
 8838         0f 85/jump-if-!= break/disp32
 8839 $emit-unconditional-jump-to-depth:label-found:
 8840         # emit unconditional jump, then return
 8841         (emit-indent *(ebp+8) *Curr-block-depth)
 8842         (write-buffered *(ebp+8) "e9/jump ")
 8843         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8844         (write-buffered *(ebp+8) %eax)
 8845         (write-buffered *(ebp+8) ":")
 8846         (write-buffered *(ebp+8) *(ebp+0x14))
 8847         (write-buffered *(ebp+8) "/disp32\n")
 8848         eb/jump $emit-unconditional-jump-to-depth:end/disp8
 8849       }
 8850       # curr -= 12
 8851       81 5/subop/subtract %esi 0xc/imm32
 8852       e9/jump loop/disp32
 8853     }
 8854     # TODO: error if no label at 'depth' was found
 8855 $emit-unconditional-jump-to-depth:end:
 8856     # . restore registers
 8857     5e/pop-to-esi
 8858     5b/pop-to-ebx
 8859     5a/pop-to-edx
 8860     59/pop-to-ecx
 8861     58/pop-to-eax
 8862     # . epilogue
 8863     89/<- %esp 5/r32/ebp
 8864     5d/pop-to-ebp
 8865     c3/return
 8866 
 8867 # emit clean-up code for 'vars' until some block depth
 8868 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 8869 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
 8870     # . prologue
 8871     55/push-ebp
 8872     89/<- %ebp 4/r32/esp
 8873     # . save registers
 8874     50/push-eax
 8875     51/push-ecx
 8876     52/push-edx
 8877     53/push-ebx
 8878     56/push-esi
 8879 #?     (write-buffered Stderr "--- cleanup\n")
 8880 #?     (flush Stderr)
 8881     # ecx = vars
 8882     8b/-> *(ebp+0xc) 1/r32/ecx
 8883     # var esi: int = vars->top
 8884     8b/-> *ecx 6/r32/esi
 8885     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 8886     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
 8887     # var min/ecx: (addr handle var) = vars->data
 8888     81 0/subop/add %ecx 8/imm32
 8889     # edx = until-block-depth
 8890     8b/-> *(ebp+0x10) 2/r32/edx
 8891     {
 8892 $emit-cleanup-code-until-depth:loop:
 8893       # if (curr < min) break
 8894       39/compare %esi 1/r32/ecx
 8895       0f 82/jump-if-addr< break/disp32
 8896       # var v/ebx: (addr var) = lookup(*curr)
 8897       (lookup *esi *(esi+4))  # => eax
 8898       89/<- %ebx 0/r32/eax
 8899 #?       (lookup *ebx *(ebx+4))  # Var-name
 8900 #?       (write-buffered Stderr "var ")
 8901 #?       (write-buffered Stderr %eax)
 8902 #?       (write-buffered Stderr Newline)
 8903 #?       (flush Stderr)
 8904       # if (v->block-depth < until-block-depth) break
 8905       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 8906       0f 8c/jump-if-< break/disp32
 8907       # if v is in a register
 8908       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 8909       {
 8910         0f 84/jump-if-= break/disp32
 8911         {
 8912 $emit-cleanup-code-until-depth:check-for-previous-spill:
 8913           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
 8914           3d/compare-eax-and 0/imm32/false
 8915           74/jump-if-= break/disp8
 8916 $emit-cleanup-code-until-depth:reclaim-var-in-register:
 8917           (emit-indent *(ebp+8) *Curr-block-depth)
 8918           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 8919           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 8920           (write-buffered *(ebp+8) %eax)
 8921           (write-buffered *(ebp+8) Newline)
 8922         }
 8923         eb/jump $emit-cleanup-code-until-depth:continue/disp8
 8924       }
 8925       # otherwise v is on the stack
 8926       {
 8927         75/jump-if-!= break/disp8
 8928 $emit-cleanup-code-until-depth:var-on-stack:
 8929         (size-of %ebx)  # => eax
 8930         # don't emit code for labels
 8931         3d/compare-eax-and 0/imm32
 8932         74/jump-if-= break/disp8
 8933 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
 8934         (emit-indent *(ebp+8) *Curr-block-depth)
 8935         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 8936         (print-int32-buffered *(ebp+8) %eax)
 8937         (write-buffered *(ebp+8) "/imm32\n")
 8938       }
 8939 $emit-cleanup-code-until-depth:continue:
 8940       # curr -= 12
 8941       81 5/subop/subtract %esi 0xc/imm32
 8942       e9/jump loop/disp32
 8943     }
 8944 $emit-cleanup-code-until-depth:end:
 8945     # . restore registers
 8946     5e/pop-to-esi
 8947     5b/pop-to-ebx
 8948     5a/pop-to-edx
 8949     59/pop-to-ecx
 8950     58/pop-to-eax
 8951     # . epilogue
 8952     89/<- %esp 5/r32/ebp
 8953     5d/pop-to-ebp
 8954     c3/return
 8955 
 8956 # emit clean-up code for 'vars' until a given label is encountered
 8957 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 8958 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
 8959     # . prologue
 8960     55/push-ebp
 8961     89/<- %ebp 4/r32/esp
 8962     # . save registers
 8963     50/push-eax
 8964     51/push-ecx
 8965     52/push-edx
 8966     53/push-ebx
 8967     # ecx = vars
 8968     8b/-> *(ebp+0xc) 1/r32/ecx
 8969     # var eax: int = vars->top
 8970     8b/-> *ecx 0/r32/eax
 8971     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
 8972     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
 8973     # var min/ecx: (addr handle var) = vars->data
 8974     81 0/subop/add %ecx 8/imm32
 8975     {
 8976 $emit-cleanup-code-until-target:loop:
 8977       # if (curr < min) break
 8978       39/compare %edx 1/r32/ecx
 8979       0f 82/jump-if-addr< break/disp32
 8980       # var v/ebx: (handle var) = lookup(*curr)
 8981       (lookup *edx *(edx+4))  # => eax
 8982       89/<- %ebx 0/r32/eax
 8983       # if (v->name == until-block-label) break
 8984       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 8985       (string-equal? %eax *(ebp+0x10))  # => eax
 8986       3d/compare-eax-and 0/imm32/false
 8987       0f 85/jump-if-!= break/disp32
 8988       # if v is in a register
 8989       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 8990       {
 8991         0f 84/jump-if-= break/disp32
 8992         {
 8993 $emit-cleanup-code-until-target:check-for-previous-spill:
 8994           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
 8995           3d/compare-eax-and 0/imm32/false
 8996           74/jump-if-= break/disp8
 8997 $emit-cleanup-code-until-target:reclaim-var-in-register:
 8998           (emit-indent *(ebp+8) *Curr-block-depth)
 8999           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 9000           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9001           (write-buffered *(ebp+8) %eax)
 9002           (write-buffered *(ebp+8) Newline)
 9003         }
 9004         eb/jump $emit-cleanup-code-until-target:continue/disp8
 9005       }
 9006       # otherwise v is on the stack
 9007       {
 9008         75/jump-if-!= break/disp8
 9009 $emit-cleanup-code-until-target:reclaim-var-on-stack:
 9010         (size-of %ebx)  # => eax
 9011         # don't emit code for labels
 9012         3d/compare-eax-and 0/imm32
 9013         74/jump-if-= break/disp8
 9014         #
 9015         (emit-indent *(ebp+8) *Curr-block-depth)
 9016         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 9017         (print-int32-buffered *(ebp+8) %eax)
 9018         (write-buffered *(ebp+8) "/imm32\n")
 9019       }
 9020 $emit-cleanup-code-until-target:continue:
 9021       # curr -= 12
 9022       81 5/subop/subtract %edx 0xc/imm32
 9023       e9/jump loop/disp32
 9024     }
 9025 $emit-cleanup-code-until-target:end:
 9026     # . restore registers
 9027     5b/pop-to-ebx
 9028     5a/pop-to-edx
 9029     59/pop-to-ecx
 9030     58/pop-to-eax
 9031     # . epilogue
 9032     89/<- %esp 5/r32/ebp
 9033     5d/pop-to-ebp
 9034     c3/return
 9035 
 9036 # Return true if there isn't a variable in 'vars' with the same block-depth
 9037 # and register as 'v'.
 9038 # 'v' is guaranteed not to be within 'vars'.
 9039 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9040     # . prologue
 9041     55/push-ebp
 9042     89/<- %ebp 4/r32/esp
 9043     # . save registers
 9044     51/push-ecx
 9045     52/push-edx
 9046     53/push-ebx
 9047     56/push-esi
 9048     57/push-edi
 9049     # ecx = vars
 9050     8b/-> *(ebp+0xc) 1/r32/ecx
 9051     # var eax: int = vars->top
 9052     8b/-> *ecx 0/r32/eax
 9053     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
 9054     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
 9055     # var min/ecx: (addr handle var) = vars->data
 9056     8d/copy-address *(ecx+8) 1/r32/ecx
 9057     # var depth/ebx: int = v->block-depth
 9058     8b/-> *(ebp+8) 3/r32/ebx
 9059     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
 9060     # var needle/esi: (addr array byte) = v->register
 9061     8b/-> *(ebp+8) 6/r32/esi
 9062     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
 9063     89/<- %esi 0/r32/eax
 9064     {
 9065 $not-yet-spilled-this-block?:loop:
 9066       # if (curr < min) break
 9067       39/compare %edx 1/r32/ecx
 9068       0f 82/jump-if-addr< break/disp32
 9069       # var cand/edi: (addr var) = lookup(*curr)
 9070       (lookup *edx *(edx+4))  # => eax
 9071       89/<- %edi 0/r32/eax
 9072       # if (cand->block-depth < depth) break
 9073       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
 9074       0f 8c/jump-if-< break/disp32
 9075       # var cand-reg/edi: (array array byte) = cand->reg
 9076       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
 9077       89/<- %edi 0/r32/eax
 9078       # if (cand-reg == null) continue
 9079       {
 9080 $not-yet-spilled-this-block?:check-reg:
 9081         81 7/subop/compare %edi 0/imm32
 9082         0f 84/jump-if-= break/disp32
 9083         # if (cand-reg == needle) return true
 9084         (string-equal? %esi %edi)  # => eax
 9085         3d/compare-eax-and 0/imm32/false
 9086         74/jump-if-= break/disp8
 9087 $not-yet-spilled-this-block?:return-false:
 9088         b8/copy-to-eax 0/imm32/false
 9089         eb/jump $not-yet-spilled-this-block?:end/disp8
 9090       }
 9091 $not-yet-spilled-this-block?:continue:
 9092       # curr -= 12
 9093       81 5/subop/subtract %edx 0xc/imm32
 9094       e9/jump loop/disp32
 9095     }
 9096 $not-yet-spilled-this-block?:return-true:
 9097     # return true
 9098     b8/copy-to-eax 1/imm32/true
 9099 $not-yet-spilled-this-block?:end:
 9100     # . restore registers
 9101     5f/pop-to-edi
 9102     5e/pop-to-esi
 9103     5b/pop-to-ebx
 9104     5a/pop-to-edx
 9105     59/pop-to-ecx
 9106     # . epilogue
 9107     89/<- %esp 5/r32/ebp
 9108     5d/pop-to-ebp
 9109     c3/return
 9110 
 9111 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
 9112 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn-outputs: (addr list var) -> result/eax: boolean
 9113     # . prologue
 9114     55/push-ebp
 9115     89/<- %ebp 4/r32/esp
 9116     # eax = v
 9117     8b/-> *(ebp+8) 0/r32/eax
 9118     # var reg/eax: (addr array byte) = lookup(v->register)
 9119     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9120     # var target/eax: (addr var) = find-register(fn-outputs, reg)
 9121     (find-register *(ebp+0x10) %eax)  # => eax
 9122     # if (target == 0) return true
 9123     {
 9124       3d/compare-eax-and 0/imm32
 9125       75/jump-if-!= break/disp8
 9126       b8/copy-to-eax 1/imm32/true
 9127       eb/jump $will-not-write-some-register?:end/disp8
 9128     }
 9129     # return !assigns-in-stmts?(stmts, target)
 9130     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
 9131     3d/compare-eax-and 0/imm32/false
 9132     # assume: true = 1, so no need to mask with 0x000000ff
 9133     0f 94/set-if-= %al
 9134 $will-not-write-some-register?:end:
 9135     # . epilogue
 9136     89/<- %esp 5/r32/ebp
 9137     5d/pop-to-ebp
 9138     c3/return
 9139 
 9140 # return output var with matching register
 9141 # always returns false if 'reg' is null
 9142 find-register:  # fn-outputs: (addr list var), reg: (addr array byte) -> result/eax: (addr var)
 9143     # . prologue
 9144     55/push-ebp
 9145     89/<- %ebp 4/r32/esp
 9146     # . save registers
 9147     51/push-ecx
 9148     # var curr/ecx: (addr list var) = fn-outputs
 9149     8b/-> *(ebp+8) 1/r32/ecx
 9150     {
 9151 $find-register:loop:
 9152       # if (curr == 0) break
 9153       81 7/subop/compare %ecx 0/imm32
 9154       74/jump-if-= break/disp8
 9155       # eax = curr->value->register
 9156       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9157       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9158       # if (eax == reg) return curr->value
 9159 $find-register:compare:
 9160       (string-equal? *(ebp+0xc) %eax)  # => eax
 9161       {
 9162         3d/compare-eax-and 0/imm32/false
 9163         74/jump-if-= break/disp8
 9164 $find-register:found:
 9165         (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9166         eb/jump $find-register:end/disp8
 9167       }
 9168       # curr = lookup(curr->next)
 9169       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9170       89/<- %ecx 0/r32/eax
 9171       #
 9172       eb/jump loop/disp8
 9173     }
 9174 $find-register:end:
 9175     # . restore registers
 9176     59/pop-to-ecx
 9177     # . epilogue
 9178     89/<- %esp 5/r32/ebp
 9179     5d/pop-to-ebp
 9180     c3/return
 9181 
 9182 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
 9183     # . prologue
 9184     55/push-ebp
 9185     89/<- %ebp 4/r32/esp
 9186     # . save registers
 9187     51/push-ecx
 9188     # var curr/ecx: (addr list stmt) = stmts
 9189     8b/-> *(ebp+8) 1/r32/ecx
 9190     {
 9191       # if (curr == 0) break
 9192       81 7/subop/compare %ecx 0/imm32
 9193       74/jump-if-= break/disp8
 9194       # if assigns-in-stmt?(curr->value, v) return true
 9195       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9196       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
 9197       3d/compare-eax-and 0/imm32/false
 9198       75/jump-if-!= break/disp8
 9199       # curr = lookup(curr->next)
 9200       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9201       89/<- %ecx 0/r32/eax
 9202       #
 9203       eb/jump loop/disp8
 9204     }
 9205 $assigns-in-stmts?:end:
 9206     # . restore registers
 9207     59/pop-to-ecx
 9208     # . epilogue
 9209     89/<- %esp 5/r32/ebp
 9210     5d/pop-to-ebp
 9211     c3/return
 9212 
 9213 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
 9214     # . prologue
 9215     55/push-ebp
 9216     89/<- %ebp 4/r32/esp
 9217     # . save registers
 9218     51/push-ecx
 9219     # ecx = stmt
 9220     8b/-> *(ebp+8) 1/r32/ecx
 9221     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
 9222     {
 9223       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 9224       75/jump-if-!= break/disp8
 9225       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9226       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
 9227       eb/jump $assigns-in-stmt?:end/disp8
 9228     }
 9229     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
 9230     {
 9231       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 9232       75/jump-if-!= break/disp8
 9233       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
 9234       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
 9235       eb/jump $assigns-in-stmt?:end/disp8
 9236     }
 9237     # otherwise return false
 9238     b8/copy 0/imm32/false
 9239 $assigns-in-stmt?:end:
 9240     # . restore registers
 9241     59/pop-to-ecx
 9242     # . epilogue
 9243     89/<- %esp 5/r32/ebp
 9244     5d/pop-to-ebp
 9245     c3/return
 9246 
 9247 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
 9248     # . prologue
 9249     55/push-ebp
 9250     89/<- %ebp 4/r32/esp
 9251     # . save registers
 9252     51/push-ecx
 9253     # var curr/ecx: (addr stmt-var) = stmt-var
 9254     8b/-> *(ebp+8) 1/r32/ecx
 9255     {
 9256       # if (curr == 0) break
 9257       81 7/subop/compare %ecx 0/imm32
 9258       74/jump-if-= break/disp8
 9259       # eax = lookup(curr->value)
 9260       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9261       # if (eax == v  &&  curr->is-deref? == false) return true
 9262       {
 9263         39/compare *(ebp+0xc) 0/r32/eax
 9264         75/jump-if-!= break/disp8
 9265         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9266         75/jump-if-!= break/disp8
 9267         b8/copy-to-eax 1/imm32/true
 9268         eb/jump $assigns-in-stmt-vars?:end/disp8
 9269       }
 9270       # curr = lookup(curr->next)
 9271       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9272       89/<- %ecx 0/r32/eax
 9273       #
 9274       eb/jump loop/disp8
 9275     }
 9276 $assigns-in-stmt-vars?:end:
 9277     # . restore registers
 9278     59/pop-to-ecx
 9279     # . epilogue
 9280     89/<- %esp 5/r32/ebp
 9281     5d/pop-to-ebp
 9282     c3/return
 9283 
 9284 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
 9285 # v is guaranteed to be within vars
 9286 # 'start' is provided as an optimization, a pointer within vars
 9287 # *start == v
 9288 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
 9289     # . prologue
 9290     55/push-ebp
 9291     89/<- %ebp 4/r32/esp
 9292     # . save registers
 9293     51/push-ecx
 9294     52/push-edx
 9295     53/push-ebx
 9296     56/push-esi
 9297     57/push-edi
 9298     # ecx = v
 9299     8b/-> *(ebp+8) 1/r32/ecx
 9300     # var reg/edx: (addr array byte) = lookup(v->register)
 9301     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9302     89/<- %edx 0/r32/eax
 9303     # var depth/ebx: int = v->block-depth
 9304     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
 9305     # var min/ecx: (addr handle var) = vars->data
 9306     8b/-> *(ebp+0xc) 1/r32/ecx
 9307     81 0/subop/add %ecx 8/imm32
 9308     # TODO: check that start >= min and start < &vars->data[top]
 9309     # TODO: check that *start == v
 9310     # var curr/esi: (addr handle var) = start
 9311     8b/-> *(ebp+0x10) 6/r32/esi
 9312     # curr -= 8
 9313     81 5/subop/subtract %esi 8/imm32
 9314     {
 9315 $same-register-spilled-before?:loop:
 9316       # if (curr < min) break
 9317       39/compare %esi 1/r32/ecx
 9318       0f 82/jump-if-addr< break/disp32
 9319       # var x/eax: (addr var) = lookup(*curr)
 9320       (lookup *esi *(esi+4))  # => eax
 9321       # if (x->block-depth < depth) break
 9322       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
 9323       0f 8c/jump-if-< break/disp32
 9324       # if (x->register == 0) continue
 9325       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 9326       74/jump-if-= $same-register-spilled-before?:continue/disp8
 9327       # if (x->register == reg) return true
 9328       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9329       (string-equal? %eax %edx)  # => eax
 9330       3d/compare-eax-and 0/imm32/false
 9331       b8/copy-to-eax 1/imm32/true
 9332       75/jump-if-!= $same-register-spilled-before?:end/disp8
 9333 $same-register-spilled-before?:continue:
 9334       # curr -= 8
 9335       81 5/subop/subtract %esi 8/imm32
 9336       e9/jump loop/disp32
 9337     }
 9338 $same-register-spilled-before?:false:
 9339     b8/copy-to-eax 0/imm32/false
 9340 $same-register-spilled-before?:end:
 9341     # . restore registers
 9342     5f/pop-to-edi
 9343     5e/pop-to-esi
 9344     5b/pop-to-ebx
 9345     5a/pop-to-edx
 9346     59/pop-to-ecx
 9347     # . epilogue
 9348     89/<- %esp 5/r32/ebp
 9349     5d/pop-to-ebp
 9350     c3/return
 9351 
 9352 # clean up global state for 'vars' until some block depth
 9353 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int
 9354     # . prologue
 9355     55/push-ebp
 9356     89/<- %ebp 4/r32/esp
 9357     # . save registers
 9358     50/push-eax
 9359     51/push-ecx
 9360     56/push-esi
 9361     # esi = vars
 9362     8b/-> *(ebp+8) 6/r32/esi
 9363     # ecx = until-block-depth
 9364     8b/-> *(ebp+0xc) 1/r32/ecx
 9365     {
 9366 $clean-up-blocks:reclaim-loop:
 9367       # if (vars->top <= 0) break
 9368       8b/-> *esi 0/r32/eax  # Stack-top
 9369       3d/compare-eax-and 0/imm32
 9370       0f 8e/jump-if-<= break/disp32
 9371       # var v/eax: (addr var) = lookup(vars[vars->top-12])
 9372 #?       (print-int32-buffered Stderr %eax)
 9373 #?       (write-buffered Stderr ": ")
 9374 #?       (print-int32-buffered Stderr *(esi+eax-4))
 9375 #?       (write-buffered Stderr " ")
 9376 #?       (print-int32-buffered Stderr *(esi+eax))
 9377 #?       (write-buffered Stderr " ")
 9378 #?       (print-int32-buffered Stderr *(esi+eax+4))
 9379 #?       (write-buffered Stderr Newline)
 9380 #?       (flush Stderr)
 9381       (lookup *(esi+eax-4) *(esi+eax))  # vars + 8 + vars->top - 12 => eax
 9382       # if (v->block-depth < until-block-depth) break
 9383       39/compare *(eax+0x10) 1/r32/ecx  # Var-block-depth
 9384       7c/jump-if-< break/disp8
 9385       # if v is on the stack, update Curr-local-stack-offset
 9386       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 9387       {
 9388         75/jump-if-!= break/disp8
 9389 $clean-up-blocks:reclaim-var-on-stack:
 9390         (size-of %eax)  # => eax
 9391         01/add-to *Curr-local-stack-offset 0/r32/eax
 9392       }
 9393       (pop %esi)  # => eax
 9394       (pop %esi)  # => eax
 9395       (pop %esi)  # => eax
 9396       e9/jump loop/disp32
 9397     }
 9398 $clean-up-blocks:end:
 9399     # . restore registers
 9400     5e/pop-to-esi
 9401     59/pop-to-ecx
 9402     58/pop-to-eax
 9403     # . epilogue
 9404     89/<- %esp 5/r32/ebp
 9405     5d/pop-to-ebp
 9406     c3/return
 9407 
 9408 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
 9409     # . prologue
 9410     55/push-ebp
 9411     89/<- %ebp 4/r32/esp
 9412     # . save registers
 9413     50/push-eax
 9414     51/push-ecx
 9415     52/push-edx
 9416     # eax = stmt
 9417     8b/-> *(ebp+0xc) 0/r32/eax
 9418     # var v/ecx: (addr var)
 9419     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
 9420     89/<- %ecx 0/r32/eax
 9421     # v->block-depth = *Curr-block-depth
 9422     8b/-> *Curr-block-depth 0/r32/eax
 9423     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9424     # var n/edx: int = size-of(stmt->var)
 9425     (size-of %ecx)  # => eax
 9426     89/<- %edx 0/r32/eax
 9427     # *Curr-local-stack-offset -= n
 9428     29/subtract-from *Curr-local-stack-offset 2/r32/edx
 9429     # v->offset = *Curr-local-stack-offset
 9430     8b/-> *Curr-local-stack-offset 0/r32/eax
 9431     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
 9432     # if v is an array, do something special
 9433     {
 9434       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9435       (is-mu-array? %eax)  # => eax
 9436       3d/compare-eax-and 0/imm32/false
 9437       0f 84/jump-if-= break/disp32
 9438       # var array-size-without-size/edx: int = n-4
 9439       81 5/subop/subtract %edx 4/imm32
 9440       (emit-indent *(ebp+8) *Curr-block-depth)
 9441       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
 9442       (print-int32-buffered *(ebp+8) %edx)
 9443       (write-buffered *(ebp+8) ")\n")
 9444       (emit-indent *(ebp+8) *Curr-block-depth)
 9445       (write-buffered *(ebp+8) "68/push ")
 9446       (print-int32-buffered *(ebp+8) %edx)
 9447       (write-buffered *(ebp+8) "/imm32\n")
 9448       eb/jump $emit-subx-var-def:end/disp8
 9449     }
 9450     # while n > 0
 9451     {
 9452       81 7/subop/compare %edx 0/imm32
 9453       7e/jump-if-<= break/disp8
 9454       (emit-indent *(ebp+8) *Curr-block-depth)
 9455       (write-buffered *(ebp+8) "68/push 0/imm32\n")
 9456       # n -= 4
 9457       81 5/subop/subtract %edx 4/imm32
 9458       #
 9459       eb/jump loop/disp8
 9460     }
 9461 $emit-subx-var-def:end:
 9462     # . restore registers
 9463     5a/pop-to-edx
 9464     59/pop-to-ecx
 9465     58/pop-to-eax
 9466     # . epilogue
 9467     89/<- %esp 5/r32/ebp
 9468     5d/pop-to-ebp
 9469     c3/return
 9470 
 9471 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive)
 9472     # . prologue
 9473     55/push-ebp
 9474     89/<- %ebp 4/r32/esp
 9475     # . save registers
 9476     50/push-eax
 9477     51/push-ecx
 9478     # - some special-case primitives that don't actually use the 'primitives' data structure
 9479     # var op/ecx: (addr array byte) = lookup(stmt->operation)
 9480     8b/-> *(ebp+0xc) 1/r32/ecx
 9481     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 9482     89/<- %ecx 0/r32/eax
 9483     # array size
 9484     {
 9485       # if (!string-equal?(stmt->operation, "length")) break
 9486       (string-equal? %ecx "length")  # => eax
 9487       3d/compare-eax-and 0/imm32
 9488       0f 84/jump-if-= break/disp32
 9489       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc))
 9490       e9/jump $emit-subx-stmt:end/disp32
 9491     }
 9492     # index into array
 9493     {
 9494       # if (!string-equal?(stmt->operation, "index")) break
 9495       (string-equal? %ecx "index")  # => eax
 9496       3d/compare-eax-and 0/imm32
 9497       0f 84/jump-if-= break/disp32
 9498       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc))
 9499       e9/jump $emit-subx-stmt:end/disp32
 9500     }
 9501     # compute-offset for index into array
 9502     {
 9503       # if (!string-equal?(stmt->operation, "compute-offset")) break
 9504       (string-equal? %ecx "compute-offset")  # => eax
 9505       3d/compare-eax-and 0/imm32
 9506       0f 84/jump-if-= break/disp32
 9507       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc))
 9508       e9/jump $emit-subx-stmt:end/disp32
 9509     }
 9510     # get field from record
 9511     {
 9512       # if (!string-equal?(stmt->operation, "get")) break
 9513       (string-equal? %ecx "get")  # => eax
 9514       3d/compare-eax-and 0/imm32
 9515       0f 84/jump-if-= break/disp32
 9516       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
 9517       e9/jump $emit-subx-stmt:end/disp32
 9518     }
 9519     # - if stmt matches a primitive, emit it
 9520     {
 9521 $emit-subx-stmt:check-for-primitive:
 9522       # var curr/eax: (addr primitive)
 9523       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
 9524       3d/compare-eax-and 0/imm32
 9525       74/jump-if-= break/disp8
 9526 $emit-subx-stmt:primitive:
 9527       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
 9528       e9/jump $emit-subx-stmt:end/disp32
 9529     }
 9530     # - otherwise emit a call
 9531     # TODO: type-checking
 9532 $emit-subx-stmt:call:
 9533     (emit-call *(ebp+8) *(ebp+0xc))
 9534 $emit-subx-stmt:end:
 9535     # . restore registers
 9536     59/pop-to-ecx
 9537     58/pop-to-eax
 9538     # . epilogue
 9539     89/<- %esp 5/r32/ebp
 9540     5d/pop-to-ebp
 9541     c3/return
 9542 
 9543 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9544     # . prologue
 9545     55/push-ebp
 9546     89/<- %ebp 4/r32/esp
 9547     # . save registers
 9548     50/push-eax
 9549     51/push-ecx
 9550     52/push-edx
 9551     53/push-ebx
 9552     56/push-esi
 9553     # esi = stmt
 9554     8b/-> *(ebp+0xc) 6/r32/esi
 9555     # var base/ebx: (addr var) = stmt->inouts[0]->value
 9556     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9557     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9558     89/<- %ebx 0/r32/eax
 9559     # var elemsize/ecx: int = element-size(base)
 9560     (array-element-type-id %ebx)  # => eax
 9561     (size-of-type-id %eax)  # => eax
 9562     89/<- %ecx 0/r32/eax
 9563     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
 9564     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9565     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9566     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9567     89/<- %edx 0/r32/eax
 9568     # if elemsize == 1
 9569     {
 9570       81 7/subop/compare %ecx 1/imm32
 9571       75/jump-if-!= break/disp8
 9572       (emit-save-size-to *(ebp+8) %ebx %edx)
 9573       e9/jump $translate-mu-length-stmt:end/disp32
 9574     }
 9575     # if elemsize is a power of 2 less than 256
 9576     {
 9577       (power-of-2? %ecx)  # => eax
 9578       3d/compare-eax-and 0/imm32/false
 9579       74/jump-if-= break/disp8
 9580       81 7/subop/compare %ecx 0xff/imm32
 9581       7f/jump-if-> break/disp8
 9582       (emit-save-size-to *(ebp+8) %ebx %edx)
 9583       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
 9584       e9/jump $translate-mu-length-stmt:end/disp32
 9585     }
 9586     # otherwise, the complex case
 9587     # . emit register spills
 9588     {
 9589       (string-equal? %edx "eax")  # => eax
 9590       3d/compare-eax-and 0/imm32/false
 9591       75/break-if-!= break/disp8
 9592       (emit-indent *(ebp+8) *Curr-block-depth)
 9593       (write-buffered *(ebp+8) "50/push-eax\n")
 9594     }
 9595     {
 9596       (string-equal? %edx "ecx")  # => eax
 9597       3d/compare-eax-and 0/imm32/false
 9598       75/break-if-!= break/disp8
 9599       (emit-indent *(ebp+8) *Curr-block-depth)
 9600       (write-buffered *(ebp+8) "51/push-ecx\n")
 9601     }
 9602     {
 9603       (string-equal? %edx "edx")  # => eax
 9604       3d/compare-eax-and 0/imm32/false
 9605       75/break-if-!= break/disp8
 9606       (emit-indent *(ebp+8) *Curr-block-depth)
 9607       (write-buffered *(ebp+8) "52/push-edx\n")
 9608     }
 9609     # .
 9610     (emit-save-size-to *(ebp+8) %ebx "eax")
 9611     (emit-indent *(ebp+8) *Curr-block-depth)
 9612     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
 9613     (emit-indent *(ebp+8) *Curr-block-depth)
 9614     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
 9615     (print-int32-buffered *(ebp+8) %ecx)
 9616     (write-buffered *(ebp+8) "/imm32\n")
 9617     (emit-indent *(ebp+8) *Curr-block-depth)
 9618     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
 9619     {
 9620       (string-equal? %edx "eax")  # => eax
 9621       3d/compare-eax-and 0/imm32/false
 9622       75/break-if-!= break/disp8
 9623       (emit-indent *(ebp+8) *Curr-block-depth)
 9624       (write-buffered *(ebp+8) "89/<- %")
 9625       (write-buffered *(ebp+8) %edx)
 9626       (write-buffered *(ebp+8) " 0/r32/eax\n")
 9627     }
 9628     # . emit register restores
 9629     {
 9630       (string-equal? %edx "edx")  # => eax
 9631       3d/compare-eax-and 0/imm32/false
 9632       75/break-if-!= break/disp8
 9633       (emit-indent *(ebp+8) *Curr-block-depth)
 9634       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
 9635     }
 9636     {
 9637       (string-equal? %edx "ecx")  # => eax
 9638       3d/compare-eax-and 0/imm32/false
 9639       75/break-if-!= break/disp8
 9640       (emit-indent *(ebp+8) *Curr-block-depth)
 9641       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
 9642     }
 9643     {
 9644       (string-equal? %edx "eax")  # => eax
 9645       3d/compare-eax-and 0/imm32/false
 9646       75/break-if-!= break/disp8
 9647       (emit-indent *(ebp+8) *Curr-block-depth)
 9648       (write-buffered *(ebp+8) "58/pop-to-eax\n")
 9649     }
 9650 $translate-mu-length-stmt:end:
 9651     # . restore registers
 9652     5e/pop-to-esi
 9653     5b/pop-to-ebx
 9654     5a/pop-to-edx
 9655     59/pop-to-ecx
 9656     58/pop-to-eax
 9657     # . epilogue
 9658     89/<- %esp 5/r32/ebp
 9659     5d/pop-to-ebp
 9660     c3/return
 9661 
 9662 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
 9663     # . prologue
 9664     55/push-ebp
 9665     89/<- %ebp 4/r32/esp
 9666     # . save registers
 9667     50/push-eax
 9668     53/push-ebx
 9669     # ebx = base
 9670     8b/-> *(ebp+0xc) 3/r32/ebx
 9671     (emit-indent *(ebp+8) *Curr-block-depth)
 9672     (write-buffered *(ebp+8) "8b/-> *")
 9673     # if base is an (addr array ...) in a register
 9674     {
 9675       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
 9676       74/jump-if-= break/disp8
 9677 $emit-save-size-to:emit-base-from-register:
 9678       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9679       (write-buffered *(ebp+8) %eax)
 9680       eb/jump $emit-save-size-to:emit-output/disp8
 9681     }
 9682     # otherwise if base is an (array ...) on the stack
 9683     {
 9684       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
 9685       74/jump-if-= break/disp8
 9686 $emit-save-size-to:emit-base-from-stack:
 9687       (write-buffered *(ebp+8) "(ebp+")
 9688       (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
 9689       (write-buffered *(ebp+8) ")")
 9690     }
 9691 $emit-save-size-to:emit-output:
 9692     (write-buffered *(ebp+8) " ")
 9693     (get Registers *(ebp+0x10) 0xc "Registers")  # => eax
 9694     (print-int32-buffered *(ebp+8) *eax)
 9695     (write-buffered *(ebp+8) "/r32\n")
 9696 $emit-save-size-to:end:
 9697     # . restore registers
 9698     5b/pop-to-ebx
 9699     58/pop-to-eax
 9700     # . epilogue
 9701     89/<- %esp 5/r32/ebp
 9702     5d/pop-to-ebp
 9703     c3/return
 9704 
 9705 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
 9706     # . prologue
 9707     55/push-ebp
 9708     89/<- %ebp 4/r32/esp
 9709     # . save registers
 9710     50/push-eax
 9711     #
 9712     (emit-indent *(ebp+8) *Curr-block-depth)
 9713     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
 9714     (write-buffered *(ebp+8) *(ebp+0xc))
 9715     (write-buffered *(ebp+8) Space)
 9716     (num-shift-rights *(ebp+0x10))  # => eax
 9717     (print-int32-buffered *(ebp+8) %eax)
 9718     (write-buffered *(ebp+8) "/imm8\n")
 9719 $emit-divide-by-shift-right:end:
 9720     # . restore registers
 9721     58/pop-to-eax
 9722     # . epilogue
 9723     89/<- %esp 5/r32/ebp
 9724     5d/pop-to-ebp
 9725     c3/return
 9726 
 9727 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
 9728     # . prologue
 9729     55/push-ebp
 9730     89/<- %ebp 4/r32/esp
 9731     # . save registers
 9732     51/push-ecx
 9733     # ecx = stmt
 9734     8b/-> *(ebp+0xc) 1/r32/ecx
 9735     # var base/ecx: (addr var) = stmt->inouts[0]
 9736     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9737     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9738     89/<- %ecx 0/r32/eax
 9739     # if (var->register) do one thing
 9740     {
 9741       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 9742       74/jump-if-= break/disp8
 9743       # TODO: ensure there's no dereference
 9744       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc))
 9745       eb/jump $translate-mu-index-stmt:end/disp8
 9746     }
 9747     # if (var->offset) do a different thing
 9748     {
 9749       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
 9750       74/jump-if-= break/disp8
 9751       # TODO: ensure there's no dereference
 9752       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc))
 9753       eb/jump $translate-mu-index-stmt:end/disp8
 9754     }
 9755 $translate-mu-index-stmt:end:
 9756     # . restore registers
 9757     59/pop-to-ecx
 9758     # . epilogue
 9759     89/<- %esp 5/r32/ebp
 9760     5d/pop-to-ebp
 9761     c3/return
 9762 
 9763 $translate-mu-index-stmt-with-array:error1:
 9764     (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
 9765     (flush Stderr)
 9766     # . syscall(exit, 1)
 9767     bb/copy-to-ebx  1/imm32
 9768     b8/copy-to-eax  1/imm32/exit
 9769     cd/syscall  0x80/imm8
 9770     # never gets here
 9771 
 9772 $translate-mu-index-stmt-with-array:error2:
 9773     (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
 9774     (flush Stderr)
 9775     # . syscall(exit, 1)
 9776     bb/copy-to-ebx  1/imm32
 9777     b8/copy-to-eax  1/imm32/exit
 9778     cd/syscall  0x80/imm8
 9779     # never gets here
 9780 
 9781 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt)
 9782     # . prologue
 9783     55/push-ebp
 9784     89/<- %ebp 4/r32/esp
 9785     # . save registers
 9786     50/push-eax
 9787     51/push-ecx
 9788     52/push-edx
 9789     53/push-ebx
 9790     #
 9791     (emit-indent *(ebp+8) *Curr-block-depth)
 9792     (write-buffered *(ebp+8) "8d/copy-address *(")
 9793     # TODO: ensure inouts[0] is in a register and not dereferenced
 9794 $translate-mu-index-stmt-with-array-in-register:emit-base:
 9795     # ecx = stmt
 9796     8b/-> *(ebp+0xc) 1/r32/ecx
 9797     # var base/ebx: (addr var) = inouts[0]
 9798     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9799     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9800     89/<- %ebx 0/r32/eax
 9801     # print base->register " + "
 9802     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9803     (write-buffered *(ebp+8) %eax)
 9804     (write-buffered *(ebp+8) " + ")
 9805     # var index/edx: (addr var) = inouts[1]
 9806     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9807     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
 9808     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9809     89/<- %edx 0/r32/eax
 9810     # if index->register
 9811     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
 9812     {
 9813       0f 84/jump-if-= break/disp32
 9814 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
 9815       # if index is an int
 9816       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9817       (is-simple-mu-type? %eax 1)  # int => eax
 9818       3d/compare-eax-and 0/imm32/false
 9819       {
 9820         0f 84/jump-if-= break/disp32
 9821 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
 9822         # print index->register "<<" log2(size-of(element(base->type))) " + 4) "
 9823         # . index->register "<<"
 9824         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9825         (write-buffered *(ebp+8) %eax)
 9826         (write-buffered *(ebp+8) "<<")
 9827         # . log2(size-of(element(base->type)))
 9828         # TODO: ensure size is a power of 2
 9829         (array-element-type-id %ebx)  # => eax
 9830         (size-of-type-id %eax)  # => eax
 9831         (num-shift-rights %eax)  # => eax
 9832         (print-int32-buffered *(ebp+8) %eax)
 9833         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
 9834       }
 9835       # if index->type is any other atom, abort
 9836       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9837       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 9838       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
 9839       # if index has type (offset ...)
 9840       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9841       (is-simple-mu-type? %eax 7)  # => eax
 9842       3d/compare-eax-and 0/imm32/false
 9843       {
 9844         0f 84/jump-if-= break/disp32
 9845         # print index->register
 9846 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
 9847         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9848         (write-buffered *(ebp+8) %eax)
 9849       }
 9850 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
 9851       (write-buffered *(ebp+8) " + 4) ")
 9852       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
 9853     }
 9854     # otherwise if index is a literal
 9855     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9856     (is-simple-mu-type? %eax 0)  # => eax
 9857     3d/compare-eax-and 0/imm32/false
 9858     {
 9859       0f 84/jump-if-= break/disp32
 9860 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
 9861       # var index-value/edx: int = parse-hex-int(index->name)
 9862       (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9863       (parse-hex-int %eax)  # => eax
 9864       89/<- %edx 0/r32/eax
 9865       # offset = idx-value * size-of(element(base->type))
 9866       (array-element-type-id %ebx)  # => eax
 9867       (size-of-type-id %eax)  # => eax
 9868       f7 4/subop/multiply-into-eax %edx  # clobbers edx
 9869       # offset += 4 for array size
 9870       05/add-to-eax 4/imm32
 9871       # TODO: check edx for overflow
 9872       # print offset
 9873       (print-int32-buffered *(ebp+8) %eax)
 9874       (write-buffered *(ebp+8) ") ")
 9875       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
 9876     }
 9877     # otherwise abort
 9878     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
 9879 $translate-mu-index-stmt-with-array-in-register:emit-output:
 9880     # outputs[0] "/r32"
 9881     8b/-> *(ebp+0xc) 1/r32/ecx
 9882     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9883     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9884     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9885     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
 9886     (print-int32-buffered *(ebp+8) *eax)
 9887     (write-buffered *(ebp+8) "/r32\n")
 9888 $translate-mu-index-stmt-with-array-in-register:end:
 9889     # . restore registers
 9890     5b/pop-to-ebx
 9891     5a/pop-to-edx
 9892     59/pop-to-ecx
 9893     58/pop-to-eax
 9894     # . epilogue
 9895     89/<- %esp 5/r32/ebp
 9896     5d/pop-to-ebp
 9897     c3/return
 9898 
 9899 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt)
 9900     # . prologue
 9901     55/push-ebp
 9902     89/<- %ebp 4/r32/esp
 9903     # . save registers
 9904     50/push-eax
 9905     51/push-ecx
 9906     52/push-edx
 9907     53/push-ebx
 9908     #
 9909     (emit-indent *(ebp+8) *Curr-block-depth)
 9910     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
 9911     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
 9912     8b/-> *(ebp+0xc) 0/r32/eax
 9913     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9914     89/<- %edx 0/r32/eax
 9915     # var base/ecx: (addr var) = lookup(curr->value)
 9916     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9917     89/<- %ecx 0/r32/eax
 9918     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
 9919     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9920     # var index/edx: (handle var) = curr2->value
 9921     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9922     89/<- %edx 0/r32/eax
 9923     # if index->register
 9924     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
 9925     {
 9926       0f 84/jump-if-= break/disp32
 9927 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
 9928       # if index is an int
 9929       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9930       (is-simple-mu-type? %eax 1)  # int => eax
 9931       3d/compare-eax-and 0/imm32/false
 9932       {
 9933         0f 84/jump-if-= break/disp32
 9934 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
 9935         # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4
 9936         # . inouts[1]->register "<<"
 9937         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9938         (write-buffered *(ebp+8) %eax)
 9939         (write-buffered *(ebp+8) "<<")
 9940         # . log2(size-of(element(base)))
 9941         # TODO: ensure size is a power of 2
 9942         (array-element-type-id %ecx)  # => eax
 9943         (size-of-type-id %eax)  # => eax
 9944         (num-shift-rights %eax)  # => eax
 9945         (print-int32-buffered *(ebp+8) %eax)
 9946         #
 9947         (write-buffered *(ebp+8) " + ")
 9948         #
 9949         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
 9950         05/add-to-eax 4/imm32  # for array length
 9951         (print-int32-buffered *(ebp+8) %eax)
 9952         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
 9953       }
 9954       # if index->type is any other atom, abort
 9955       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9956       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 9957       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
 9958       # if index has type (offset ...)
 9959       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 9960       (is-simple-mu-type? %eax 7)  # => eax
 9961       3d/compare-eax-and 0/imm32/false
 9962       {
 9963         0f 84/jump-if-= break/disp32
 9964         # print index->register
 9965 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
 9966         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 9967         (write-buffered *(ebp+8) %eax)
 9968       }
 9969 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
 9970       (write-buffered *(ebp+8) ") ")
 9971       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
 9972     }
 9973     # otherwise if index is a literal
 9974     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 9975     (is-simple-mu-type? %eax 0)  # => eax
 9976     3d/compare-eax-and 0/imm32/false
 9977     {
 9978       0f 84/jump-if-= break/disp32
 9979 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
 9980       # var idx-value/edx: int = parse-hex-int(index->name)
 9981       (lookup *edx *(edx+4))  # Var-name Var-name => eax
 9982       (parse-hex-int %eax)  # Var-name => eax
 9983       89/<- %edx 0/r32/eax
 9984       # offset = idx-value * size-of(element-type(base->type))
 9985       (array-element-type-id %ecx)  # => eax
 9986       (size-of-type-id %eax)  # => eax
 9987       f7 4/subop/multiply-into-eax %edx  # clobbers edx
 9988       # offset += base->offset
 9989       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
 9990       # offset += 4 for array size
 9991       05/add-to-eax 4/imm32
 9992       # TODO: check edx for overflow
 9993       # print offset
 9994       (print-int32-buffered *(ebp+8) %eax)
 9995       (write-buffered *(ebp+8) ") ")
 9996       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
 9997     }
 9998     # otherwise abort
 9999     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
10000 $translate-mu-index-stmt-with-array-on-stack:emit-output:
10001     # outputs[0] "/r32"
10002     8b/-> *(ebp+0xc) 0/r32/eax
10003     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10004     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10005     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10006     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10007     (print-int32-buffered *(ebp+8) *eax)
10008     (write-buffered *(ebp+8) "/r32\n")
10009 $translate-mu-index-stmt-with-array-on-stack:end:
10010     # . restore registers
10011     5b/pop-to-ebx
10012     5a/pop-to-edx
10013     59/pop-to-ecx
10014     58/pop-to-eax
10015     # . epilogue
10016     89/<- %esp 5/r32/ebp
10017     5d/pop-to-ebp
10018     c3/return
10019 
10020 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
10021     # . prologue
10022     55/push-ebp
10023     89/<- %ebp 4/r32/esp
10024     # . save registers
10025     50/push-eax
10026     51/push-ecx
10027     52/push-edx
10028     53/push-ebx
10029     #
10030     (emit-indent *(ebp+8) *Curr-block-depth)
10031     (write-buffered *(ebp+8) "69/multiply")
10032     # ecx = stmt
10033     8b/-> *(ebp+0xc) 1/r32/ecx
10034     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
10035     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10036     89/<- %ebx 0/r32/eax
10037 $translate-mu-compute-index-stmt:emit-index:
10038     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
10039     (emit-subx-var-as-rm32 *(ebp+8) %eax)
10040     (write-buffered *(ebp+8) Space)
10041 $translate-mu-compute-index-stmt:emit-elem-size:
10042     # var base/ebx: (addr var)
10043     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
10044     89/<- %ebx 0/r32/eax
10045     # print size-of(element(base->type))
10046     (array-element-type-id %ebx)  # => eax
10047     (size-of-type-id %eax)  # => eax
10048     (print-int32-buffered *(ebp+8) %eax)
10049     (write-buffered *(ebp+8) "/imm32 ")
10050 $translate-mu-compute-index-stmt:emit-output:
10051     # outputs[0] "/r32"
10052     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10053     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10054     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10055     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10056     (print-int32-buffered *(ebp+8) *eax)
10057     (write-buffered *(ebp+8) "/r32\n")
10058 $translate-mu-compute-index-stmt:end:
10059     # . restore registers
10060     5b/pop-to-ebx
10061     5a/pop-to-edx
10062     59/pop-to-ecx
10063     58/pop-to-eax
10064     # . epilogue
10065     89/<- %esp 5/r32/ebp
10066     5d/pop-to-ebp
10067     c3/return
10068 
10069 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
10070     # . prologue
10071     55/push-ebp
10072     89/<- %ebp 4/r32/esp
10073     # . save registers
10074     50/push-eax
10075     51/push-ecx
10076     52/push-edx
10077     #
10078     (emit-indent *(ebp+8) *Curr-block-depth)
10079     (write-buffered *(ebp+8) "8d/copy-address ")
10080     # ecx = stmt
10081     8b/-> *(ebp+0xc) 1/r32/ecx
10082     # var offset/edx: int = get offset of stmt
10083     (mu-get-offset %ecx)  # => eax
10084     89/<- %edx 0/r32/eax
10085     # var base/eax: (addr var) = stmt->inouts->value
10086     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10087     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10088     # if base is in a register
10089     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
10090     {
10091       0f 84/jump-if-= break/disp32
10092 $translate-mu-get-stmt:emit-register-input:
10093       # emit "*(" base->register " + " offset ") "
10094       (write-buffered *(ebp+8) "*(")
10095       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10096       (write-buffered *(ebp+8) %eax)
10097       (write-buffered *(ebp+8) " + ")
10098       (print-int32-buffered *(ebp+8) %edx)
10099       (write-buffered *(ebp+8) ") ")
10100       e9/jump $translate-mu-get-stmt:emit-output/disp32
10101     }
10102     # otherwise base is on the stack
10103     {
10104 $translate-mu-get-stmt:emit-stack-input:
10105       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
10106       (write-buffered *(ebp+8) "*(ebp+")
10107       03/add *(eax+0x14) 2/r32/edx  # Var-offset
10108       (print-int32-buffered *(ebp+8) %edx)
10109       (write-buffered *(ebp+8) ") ")
10110       eb/jump $translate-mu-get-stmt:emit-output/disp8
10111     }
10112 $translate-mu-get-stmt:emit-output:
10113     # var output/eax: (addr var) = stmt->outputs->value
10114     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10115     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10116     # emit offset->register "/r32"
10117     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10118     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10119     (print-int32-buffered *(ebp+8) *eax)
10120     (write-buffered *(ebp+8) "/r32\n")
10121 $translate-mu-get-stmt:end:
10122     # . restore registers
10123     5a/pop-to-edx
10124     59/pop-to-ecx
10125     58/pop-to-eax
10126     # . epilogue
10127     89/<- %esp 5/r32/ebp
10128     5d/pop-to-ebp
10129     c3/return
10130 
10131 array-element-type-id:  # v: (addr var) -> result/eax: type-id
10132     # precondition: n is positive
10133     # . prologue
10134     55/push-ebp
10135     89/<- %ebp 4/r32/esp
10136     #
10137     8b/-> *(ebp+8) 0/r32/eax
10138     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10139     # TODO: ensure type->left is 'addr'
10140     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
10141     # TODO: ensure that type->right is non-null
10142     # TODO: ensure that type->right->left is 'array'
10143     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
10144     # TODO: ensure that type->right->right is non-null
10145     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
10146     8b/-> *(eax+4) 0/r32/eax  # Tree-value
10147 $array-element-type-id:end:
10148     # . epilogue
10149     89/<- %esp 5/r32/ebp
10150     5d/pop-to-ebp
10151     c3/return
10152 
10153 power-of-2?:  # n: int -> result/eax: boolean
10154     # precondition: n is positive
10155     # . prologue
10156     55/push-ebp
10157     89/<- %ebp 4/r32/esp
10158     # eax = n
10159     8b/-> *(ebp+8) 0/r32/eax
10160     # if (n < 0) abort
10161     3d/compare-eax-with 0/imm32
10162     0f 8c/jump-if-< $power-of-2?:abort/disp32
10163     # var tmp/eax: int = n-1
10164     48/decrement-eax
10165     # var tmp2/eax: int = n & tmp
10166     23/and-> *(ebp+8) 0/r32/eax
10167     # return (tmp2 == 0)
10168     3d/compare-eax-and 0/imm32
10169     0f 94/set-byte-if-= %al
10170     81 4/subop/and %eax 0xff/imm32
10171 $power-of-2?:end:
10172     # . epilogue
10173     89/<- %esp 5/r32/ebp
10174     5d/pop-to-ebp
10175     c3/return
10176 
10177 $power-of-2?:abort:
10178     (write-buffered Stderr "power-of-2?: negative number\n")
10179     (flush Stderr)
10180     # . syscall(exit, 1)
10181     bb/copy-to-ebx  1/imm32
10182     b8/copy-to-eax  1/imm32/exit
10183     cd/syscall  0x80/imm8
10184     # never gets here
10185 
10186 num-shift-rights:  # n: int -> result/eax: int
10187     # precondition: n is a positive power of 2
10188     # . prologue
10189     55/push-ebp
10190     89/<- %ebp 4/r32/esp
10191     # . save registers
10192     51/push-ecx
10193     # var curr/ecx: int = n
10194     8b/-> *(ebp+8) 1/r32/ecx
10195     # result = 0
10196     b8/copy-to-eax 0/imm32
10197     {
10198       # if (curr <= 1) break
10199       81 7/subop/compare %ecx 1/imm32
10200       7e/jump-if-<= break/disp8
10201       40/increment-eax
10202       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
10203       eb/jump loop/disp8
10204     }
10205 $num-shift-rights:end:
10206     # . restore registers
10207     59/pop-to-ecx
10208     # . epilogue
10209     89/<- %esp 5/r32/ebp
10210     5d/pop-to-ebp
10211     c3/return
10212 
10213 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
10214     # . prologue
10215     55/push-ebp
10216     89/<- %ebp 4/r32/esp
10217     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
10218     8b/-> *(ebp+8) 0/r32/eax
10219     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10220     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
10221     # var output-var/eax: (addr var) = second-inout->value
10222     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10223 #?     (write-buffered Stderr "mu-get-offset: ")
10224 #?     (print-int32-buffered Stderr %eax)
10225 #?     (write-buffered Stderr " name: ")
10226 #?     50/push-eax
10227 #?     (lookup *eax *(eax+4))  # Var-name
10228 #?     (write-buffered Stderr %eax)
10229 #?     58/pop-to-eax
10230 #?     (write-buffered Stderr Newline)
10231 #?     (flush Stderr)
10232     # return output-var->stack-offset
10233     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
10234 #?     (write-buffered Stderr "=> ")
10235 #?     (print-int32-buffered Stderr %eax)
10236 #?     (write-buffered Stderr Newline)
10237 #?     (flush Stderr)
10238 $emit-get-offset:end:
10239     # . epilogue
10240     89/<- %esp 5/r32/ebp
10241     5d/pop-to-ebp
10242     c3/return
10243 
10244 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn-outputs: (addr list var)
10245     # . prologue
10246     55/push-ebp
10247     89/<- %ebp 4/r32/esp
10248     # . save registers
10249     50/push-eax
10250     51/push-ecx
10251     56/push-esi
10252     # esi = block
10253     8b/-> *(ebp+0xc) 6/r32/esi
10254     # block->var->block-depth = *Curr-block-depth
10255     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
10256     8b/-> *Curr-block-depth 1/r32/ecx
10257     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
10258     # var stmts/eax: (addr list stmt) = lookup(block->statements)
10259     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
10260     #
10261     {
10262 $emit-subx-block:check-empty:
10263       3d/compare-eax-and 0/imm32
10264       0f 84/jump-if-= break/disp32
10265       (emit-indent *(ebp+8) *Curr-block-depth)
10266       (write-buffered *(ebp+8) "{\n")
10267       # var v/ecx: (addr var) = lookup(block->var)
10268       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
10269       89/<- %ecx 0/r32/eax
10270       #
10271       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10272       (write-buffered *(ebp+8) %eax)
10273       (write-buffered *(ebp+8) ":loop:\n")
10274       ff 0/subop/increment *Curr-block-depth
10275       (push *(ebp+0x10) *(esi+0xc))  # Block-var
10276       (push *(ebp+0x10) *(esi+0x10))  # Block-var
10277       (push *(ebp+0x10) 0)  # false
10278       # emit block->statements
10279       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
10280       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14))
10281       (pop *(ebp+0x10))  # => eax
10282       (pop *(ebp+0x10))  # => eax
10283       (pop *(ebp+0x10))  # => eax
10284       ff 1/subop/decrement *Curr-block-depth
10285       (emit-indent *(ebp+8) *Curr-block-depth)
10286       (write-buffered *(ebp+8) "}\n")
10287       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10288       (write-buffered *(ebp+8) %eax)
10289       (write-buffered *(ebp+8) ":break:\n")
10290     }
10291 $emit-subx-block:end:
10292     # . restore registers
10293     5e/pop-to-esi
10294     59/pop-to-ecx
10295     58/pop-to-eax
10296     # . epilogue
10297     89/<- %esp 5/r32/ebp
10298     5d/pop-to-ebp
10299     c3/return
10300 
10301 # Primitives supported
10302 # See mu_instructions for a summary of this linked-list data structure.
10303 #
10304 # For each operation, put variants with hard-coded registers before flexible ones.
10305 #
10306 # Unfortunately, our restrictions on addresses require that various fields in
10307 # primitives be handles, which complicates these definitions.
10308 #   - we need to insert dummy fields all over the place for fake alloc-ids
10309 #   - we can't use our syntax sugar of quoted literals for string fields
10310 #
10311 # Fake alloc-ids are needed because our type definitions up top require
10312 # handles but it's clearer to statically allocate these long-lived objects.
10313 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
10314 #
10315 # Every 'object' below starts with a fake alloc-id. It may also contain other
10316 # fake alloc-ids for various handle fields.
10317 #
10318 # I think of objects starting with a fake alloc-id as having type 'payload'.
10319 # It's not really intended to be created dynamically; for that use `allocate`
10320 # as usual.
10321 #
10322 # Idea for a notation to simplify such definitions:
10323 #   _Primitive-increment-eax:  # (payload primitive)
10324 #     0x11/alloc-id:fake:payload
10325 #     0x11 @(0x11 "increment")  # name
10326 #     0 0                       # inouts
10327 #     0x11 @(0x11/payload
10328 #            0x11 @(0x11/payload  # List-value
10329 #                   0 0             # Var-name
10330 #                   0x11 @(0x11     # Var-type
10331 #                          1/is-atom
10332 #                          1/value 0/unused   # Tree-left
10333 #                          0 0                # Tree-right
10334 #                         )
10335 #                   1               # block-depth
10336 #                   0               # stack-offset
10337 #                   0x11 @(0x11 "eax")  # Var-register
10338 #                  )
10339 #            0 0)                 # List-next
10340 #     ...
10341 #     _Primitive-increment-ecx/imm32/next
10342 #   ...
10343 # Awfully complex and non-obvious. But also clearly signals there's something
10344 # to learn here, so may be worth trying.
10345 #
10346 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
10347 #
10348 # For now we'll continue to just use comments and manually ensure they stay up
10349 # to date.
10350 == data
10351 Primitives:  # (addr primitive)
10352 # - increment/decrement
10353 _Primitive-increment-eax:  # (addr primitive)
10354     # var/eax <- increment => 40/increment-eax
10355     0x11/imm32/alloc-id:fake
10356     _string-increment/imm32/name
10357     0/imm32/no-inouts
10358     0/imm32/no-inouts
10359     0x11/imm32/alloc-id:fake
10360     Single-int-var-in-eax/imm32/outputs
10361     0x11/imm32/alloc-id:fake
10362     _string_40_increment_eax/imm32/subx-name
10363     0/imm32/no-rm32
10364     0/imm32/no-r32
10365     0/imm32/no-imm32
10366     0/imm32/no-disp32
10367     0/imm32/output-is-write-only
10368     0x11/imm32/alloc-id:fake
10369     _Primitive-increment-ecx/imm32/next
10370 _Primitive-increment-ecx:  # (payload primitive)
10371     0x11/imm32/alloc-id:fake:payload
10372     # var/ecx <- increment => 41/increment-ecx
10373     0x11/imm32/alloc-id:fake
10374     _string-increment/imm32/name
10375     0/imm32/no-inouts
10376     0/imm32/no-inouts
10377     0x11/imm32/alloc-id:fake
10378     Single-int-var-in-ecx/imm32/outputs
10379     0x11/imm32/alloc-id:fake
10380     _string_41_increment_ecx/imm32/subx-name
10381     0/imm32/no-rm32
10382     0/imm32/no-r32
10383     0/imm32/no-imm32
10384     0/imm32/no-disp32
10385     0/imm32/output-is-write-only
10386     0x11/imm32/alloc-id:fake
10387     _Primitive-increment-edx/imm32/next
10388 _Primitive-increment-edx:  # (payload primitive)
10389     0x11/imm32/alloc-id:fake:payload
10390     # var/edx <- increment => 42/increment-edx
10391     0x11/imm32/alloc-id:fake
10392     _string-increment/imm32/name
10393     0/imm32/no-inouts
10394     0/imm32/no-inouts
10395     0x11/imm32/alloc-id:fake
10396     Single-int-var-in-edx/imm32/outputs
10397     0x11/imm32/alloc-id:fake
10398     _string_42_increment_edx/imm32/subx-name
10399     0/imm32/no-rm32
10400     0/imm32/no-r32
10401     0/imm32/no-imm32
10402     0/imm32/no-disp32
10403     0/imm32/output-is-write-only
10404     0x11/imm32/alloc-id:fake
10405     _Primitive-increment-ebx/imm32/next
10406 _Primitive-increment-ebx:  # (payload primitive)
10407     0x11/imm32/alloc-id:fake:payload
10408     # var/ebx <- increment => 43/increment-ebx
10409     0x11/imm32/alloc-id:fake
10410     _string-increment/imm32/name
10411     0/imm32/no-inouts
10412     0/imm32/no-inouts
10413     0x11/imm32/alloc-id:fake
10414     Single-int-var-in-ebx/imm32/outputs
10415     0x11/imm32/alloc-id:fake
10416     _string_43_increment_ebx/imm32/subx-name
10417     0/imm32/no-rm32
10418     0/imm32/no-r32
10419     0/imm32/no-imm32
10420     0/imm32/no-disp32
10421     0/imm32/output-is-write-only
10422     0x11/imm32/alloc-id:fake
10423     _Primitive-increment-esi/imm32/next
10424 _Primitive-increment-esi:  # (payload primitive)
10425     0x11/imm32/alloc-id:fake:payload
10426     # var/esi <- increment => 46/increment-esi
10427     0x11/imm32/alloc-id:fake
10428     _string-increment/imm32/name
10429     0/imm32/no-inouts
10430     0/imm32/no-inouts
10431     0x11/imm32/alloc-id:fake
10432     Single-int-var-in-esi/imm32/outputs
10433     0x11/imm32/alloc-id:fake
10434     _string_46_increment_esi/imm32/subx-name
10435     0/imm32/no-rm32
10436     0/imm32/no-r32
10437     0/imm32/no-imm32
10438     0/imm32/no-disp32
10439     0/imm32/output-is-write-only
10440     0x11/imm32/alloc-id:fake
10441     _Primitive-increment-edi/imm32/next
10442 _Primitive-increment-edi:  # (payload primitive)
10443     0x11/imm32/alloc-id:fake:payload
10444     # var/edi <- increment => 47/increment-edi
10445     0x11/imm32/alloc-id:fake
10446     _string-increment/imm32/name
10447     0/imm32/no-inouts
10448     0/imm32/no-inouts
10449     0x11/imm32/alloc-id:fake
10450     Single-int-var-in-edi/imm32/outputs
10451     0x11/imm32/alloc-id:fake
10452     _string_47_increment_edi/imm32/subx-name
10453     0/imm32/no-rm32
10454     0/imm32/no-r32
10455     0/imm32/no-imm32
10456     0/imm32/no-disp32
10457     0/imm32/output-is-write-only
10458     0x11/imm32/alloc-id:fake
10459     _Primitive-decrement-eax/imm32/next
10460 _Primitive-decrement-eax:  # (payload primitive)
10461     0x11/imm32/alloc-id:fake:payload
10462     # var/eax <- decrement => 48/decrement-eax
10463     0x11/imm32/alloc-id:fake
10464     _string-decrement/imm32/name
10465     0/imm32/no-inouts
10466     0/imm32/no-inouts
10467     0x11/imm32/alloc-id:fake
10468     Single-int-var-in-eax/imm32/outputs
10469     0x11/imm32/alloc-id:fake
10470     _string_48_decrement_eax/imm32/subx-name
10471     0/imm32/no-rm32
10472     0/imm32/no-r32
10473     0/imm32/no-imm32
10474     0/imm32/no-disp32
10475     0/imm32/output-is-write-only
10476     0x11/imm32/alloc-id:fake
10477     _Primitive-decrement-ecx/imm32/next
10478 _Primitive-decrement-ecx:  # (payload primitive)
10479     0x11/imm32/alloc-id:fake:payload
10480     # var/ecx <- decrement => 49/decrement-ecx
10481     0x11/imm32/alloc-id:fake
10482     _string-decrement/imm32/name
10483     0/imm32/no-inouts
10484     0/imm32/no-inouts
10485     0x11/imm32/alloc-id:fake
10486     Single-int-var-in-ecx/imm32/outputs
10487     0x11/imm32/alloc-id:fake
10488     _string_49_decrement_ecx/imm32/subx-name
10489     0/imm32/no-rm32
10490     0/imm32/no-r32
10491     0/imm32/no-imm32
10492     0/imm32/no-disp32
10493     0/imm32/output-is-write-only
10494     0x11/imm32/alloc-id:fake
10495     _Primitive-decrement-edx/imm32/next
10496 _Primitive-decrement-edx:  # (payload primitive)
10497     0x11/imm32/alloc-id:fake:payload
10498     # var/edx <- decrement => 4a/decrement-edx
10499     0x11/imm32/alloc-id:fake
10500     _string-decrement/imm32/name
10501     0/imm32/no-inouts
10502     0/imm32/no-inouts
10503     0x11/imm32/alloc-id:fake
10504     Single-int-var-in-edx/imm32/outputs
10505     0x11/imm32/alloc-id:fake
10506     _string_4a_decrement_edx/imm32/subx-name
10507     0/imm32/no-rm32
10508     0/imm32/no-r32
10509     0/imm32/no-imm32
10510     0/imm32/no-disp32
10511     0/imm32/output-is-write-only
10512     0x11/imm32/alloc-id:fake
10513     _Primitive-decrement-ebx/imm32/next
10514 _Primitive-decrement-ebx:  # (payload primitive)
10515     0x11/imm32/alloc-id:fake:payload
10516     # var/ebx <- decrement => 4b/decrement-ebx
10517     0x11/imm32/alloc-id:fake
10518     _string-decrement/imm32/name
10519     0/imm32/no-inouts
10520     0/imm32/no-inouts
10521     0x11/imm32/alloc-id:fake
10522     Single-int-var-in-ebx/imm32/outputs
10523     0x11/imm32/alloc-id:fake
10524     _string_4b_decrement_ebx/imm32/subx-name
10525     0/imm32/no-rm32
10526     0/imm32/no-r32
10527     0/imm32/no-imm32
10528     0/imm32/no-disp32
10529     0/imm32/output-is-write-only
10530     0x11/imm32/alloc-id:fake
10531     _Primitive-decrement-esi/imm32/next
10532 _Primitive-decrement-esi:  # (payload primitive)
10533     0x11/imm32/alloc-id:fake:payload
10534     # var/esi <- decrement => 4e/decrement-esi
10535     0x11/imm32/alloc-id:fake
10536     _string-decrement/imm32/name
10537     0/imm32/no-inouts
10538     0/imm32/no-inouts
10539     0x11/imm32/alloc-id:fake
10540     Single-int-var-in-esi/imm32/outputs
10541     0x11/imm32/alloc-id:fake
10542     _string_4e_decrement_esi/imm32/subx-name
10543     0/imm32/no-rm32
10544     0/imm32/no-r32
10545     0/imm32/no-imm32
10546     0/imm32/no-disp32
10547     0/imm32/output-is-write-only
10548     0x11/imm32/alloc-id:fake
10549     _Primitive-decrement-edi/imm32/next
10550 _Primitive-decrement-edi:  # (payload primitive)
10551     0x11/imm32/alloc-id:fake:payload
10552     # var/edi <- decrement => 4f/decrement-edi
10553     0x11/imm32/alloc-id:fake
10554     _string-decrement/imm32/name
10555     0/imm32/no-inouts
10556     0/imm32/no-inouts
10557     0x11/imm32/alloc-id:fake
10558     Single-int-var-in-edi/imm32/outputs
10559     0x11/imm32/alloc-id:fake
10560     _string_4f_decrement_edi/imm32/subx-name
10561     0/imm32/no-rm32
10562     0/imm32/no-r32
10563     0/imm32/no-imm32
10564     0/imm32/no-disp32
10565     0/imm32/output-is-write-only
10566     0x11/imm32/alloc-id:fake
10567     _Primitive-increment-mem/imm32/next
10568 _Primitive-increment-mem:  # (payload primitive)
10569     0x11/imm32/alloc-id:fake:payload
10570     # increment var => ff 0/subop/increment *(ebp+__)
10571     0x11/imm32/alloc-id:fake
10572     _string-increment/imm32/name
10573     0x11/imm32/alloc-id:fake
10574     Single-int-var-in-mem/imm32/inouts
10575     0/imm32/no-outputs
10576     0/imm32/no-outputs
10577     0x11/imm32/alloc-id:fake
10578     _string_ff_subop_increment/imm32/subx-name
10579     1/imm32/rm32-is-first-inout
10580     0/imm32/no-r32
10581     0/imm32/no-imm32
10582     0/imm32/no-disp32
10583     0/imm32/output-is-write-only
10584     0x11/imm32/alloc-id:fake
10585     _Primitive-increment-reg/imm32/next
10586 _Primitive-increment-reg:  # (payload primitive)
10587     0x11/imm32/alloc-id:fake:payload
10588     # var/reg <- increment => ff 0/subop/increment %__
10589     0x11/imm32/alloc-id:fake
10590     _string-increment/imm32/name
10591     0/imm32/no-inouts
10592     0/imm32/no-inouts
10593     0x11/imm32/alloc-id:fake
10594     Single-int-var-in-some-register/imm32/outputs
10595     0x11/imm32/alloc-id:fake
10596     _string_ff_subop_increment/imm32/subx-name
10597     3/imm32/rm32-is-first-output
10598     0/imm32/no-r32
10599     0/imm32/no-imm32
10600     0/imm32/no-disp32
10601     0/imm32/output-is-write-only
10602     0x11/imm32/alloc-id:fake
10603     _Primitive-decrement-mem/imm32/next
10604 _Primitive-decrement-mem:  # (payload primitive)
10605     0x11/imm32/alloc-id:fake:payload
10606     # decrement var => ff 1/subop/decrement *(ebp+__)
10607     0x11/imm32/alloc-id:fake
10608     _string-decrement/imm32/name
10609     0x11/imm32/alloc-id:fake
10610     Single-int-var-in-mem/imm32/inouts
10611     0/imm32/no-outputs
10612     0/imm32/no-outputs
10613     0x11/imm32/alloc-id:fake
10614     _string_ff_subop_decrement/imm32/subx-name
10615     1/imm32/rm32-is-first-inout
10616     0/imm32/no-r32
10617     0/imm32/no-imm32
10618     0/imm32/no-disp32
10619     0/imm32/output-is-write-only
10620     0x11/imm32/alloc-id:fake
10621     _Primitive-decrement-reg/imm32/next
10622 _Primitive-decrement-reg:  # (payload primitive)
10623     0x11/imm32/alloc-id:fake:payload
10624     # var/reg <- decrement => ff 1/subop/decrement %__
10625     0x11/imm32/alloc-id:fake
10626     _string-decrement/imm32/name
10627     0/imm32/no-inouts
10628     0/imm32/no-inouts
10629     0x11/imm32/alloc-id:fake
10630     Single-int-var-in-some-register/imm32/outputs
10631     0x11/imm32/alloc-id:fake
10632     _string_ff_subop_decrement/imm32/subx-name
10633     3/imm32/rm32-is-first-output
10634     0/imm32/no-r32
10635     0/imm32/no-imm32
10636     0/imm32/no-disp32
10637     0/imm32/output-is-write-only
10638     0x11/imm32/alloc-id:fake
10639     _Primitive-add-to-eax/imm32/next
10640 # - add
10641 _Primitive-add-to-eax:  # (payload primitive)
10642     0x11/imm32/alloc-id:fake:payload
10643     # var/eax <- add lit => 05/add-to-eax lit/imm32
10644     0x11/imm32/alloc-id:fake
10645     _string-add/imm32/name
10646     0x11/imm32/alloc-id:fake
10647     Single-lit-var/imm32/inouts
10648     0x11/imm32/alloc-id:fake
10649     Single-int-var-in-eax/imm32/outputs
10650     0x11/imm32/alloc-id:fake
10651     _string_05_add_to_eax/imm32/subx-name
10652     0/imm32/no-rm32
10653     0/imm32/no-r32
10654     1/imm32/imm32-is-first-inout
10655     0/imm32/no-disp32
10656     0/imm32/output-is-write-only
10657     0x11/imm32/alloc-id:fake
10658     _Primitive-add-reg-to-reg/imm32/next
10659 _Primitive-add-reg-to-reg:  # (payload primitive)
10660     0x11/imm32/alloc-id:fake:payload
10661     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
10662     0x11/imm32/alloc-id:fake
10663     _string-add/imm32/name
10664     0x11/imm32/alloc-id:fake
10665     Single-int-var-in-some-register/imm32/inouts
10666     0x11/imm32/alloc-id:fake
10667     Single-int-var-in-some-register/imm32/outputs
10668     0x11/imm32/alloc-id:fake
10669     _string_01_add_to/imm32/subx-name
10670     3/imm32/rm32-is-first-output
10671     1/imm32/r32-is-first-inout
10672     0/imm32/no-imm32
10673     0/imm32/no-disp32
10674     0/imm32/output-is-write-only
10675     0x11/imm32/alloc-id:fake
10676     _Primitive-add-reg-to-mem/imm32/next
10677 _Primitive-add-reg-to-mem:  # (payload primitive)
10678     0x11/imm32/alloc-id:fake:payload
10679     # add-to var1 var2/reg => 01/add-to var1 var2/r32
10680     0x11/imm32/alloc-id:fake
10681     _string-add-to/imm32/name
10682     0x11/imm32/alloc-id:fake
10683     Two-args-int-stack-int-reg/imm32/inouts
10684     0/imm32/no-outputs
10685     0/imm32/no-outputs
10686     0x11/imm32/alloc-id:fake
10687     _string_01_add_to/imm32/subx-name
10688     1/imm32/rm32-is-first-inout
10689     2/imm32/r32-is-second-inout
10690     0/imm32/no-imm32
10691     0/imm32/no-disp32
10692     0/imm32/output-is-write-only
10693     0x11/imm32/alloc-id:fake
10694     _Primitive-add-mem-to-reg/imm32/next
10695 _Primitive-add-mem-to-reg:  # (payload primitive)
10696     0x11/imm32/alloc-id:fake:payload
10697     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
10698     0x11/imm32/alloc-id:fake
10699     _string-add/imm32/name
10700     0x11/imm32/alloc-id:fake
10701     Single-int-var-in-mem/imm32/inouts
10702     0x11/imm32/alloc-id:fake
10703     Single-int-var-in-some-register/imm32/outputs
10704     0x11/imm32/alloc-id:fake
10705     _string_03_add/imm32/subx-name
10706     1/imm32/rm32-is-first-inout
10707     3/imm32/r32-is-first-output
10708     0/imm32/no-imm32
10709     0/imm32/no-disp32
10710     0/imm32/output-is-write-only
10711     0x11/imm32/alloc-id:fake
10712     _Primitive-add-lit-to-reg/imm32/next
10713 _Primitive-add-lit-to-reg:  # (payload primitive)
10714     0x11/imm32/alloc-id:fake:payload
10715     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
10716     0x11/imm32/alloc-id:fake
10717     _string-add/imm32/name
10718     0x11/imm32/alloc-id:fake
10719     Single-lit-var/imm32/inouts
10720     0x11/imm32/alloc-id:fake
10721     Single-int-var-in-some-register/imm32/outputs
10722     0x11/imm32/alloc-id:fake
10723     _string_81_subop_add/imm32/subx-name
10724     3/imm32/rm32-is-first-output
10725     0/imm32/no-r32
10726     1/imm32/imm32-is-first-inout
10727     0/imm32/no-disp32
10728     0/imm32/output-is-write-only
10729     0x11/imm32/alloc-id:fake
10730     _Primitive-add-lit-to-mem/imm32/next
10731 _Primitive-add-lit-to-mem:  # (payload primitive)
10732     0x11/imm32/alloc-id:fake:payload
10733     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
10734     0x11/imm32/alloc-id:fake
10735     _string-add-to/imm32/name
10736     0x11/imm32/alloc-id:fake
10737     Int-var-and-literal/imm32/inouts
10738     0/imm32/no-outputs
10739     0/imm32/no-outputs
10740     0x11/imm32/alloc-id:fake
10741     _string_81_subop_add/imm32/subx-name
10742     1/imm32/rm32-is-first-inout
10743     0/imm32/no-r32
10744     2/imm32/imm32-is-second-inout
10745     0/imm32/no-disp32
10746     0/imm32/output-is-write-only
10747     0x11/imm32/alloc-id:fake
10748     _Primitive-subtract-from-eax/imm32/next
10749 # - subtract
10750 _Primitive-subtract-from-eax:  # (payload primitive)
10751     0x11/imm32/alloc-id:fake:payload
10752     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
10753     0x11/imm32/alloc-id:fake
10754     _string-subtract/imm32/name
10755     0x11/imm32/alloc-id:fake
10756     Single-lit-var/imm32/inouts
10757     0x11/imm32/alloc-id:fake
10758     Single-int-var-in-eax/imm32/outputs
10759     0x11/imm32/alloc-id:fake
10760     _string_2d_subtract_from_eax/imm32/subx-name
10761     0/imm32/no-rm32
10762     0/imm32/no-r32
10763     1/imm32/imm32-is-first-inout
10764     0/imm32/no-disp32
10765     0/imm32/output-is-write-only
10766     0x11/imm32/alloc-id:fake
10767     _Primitive-subtract-reg-from-reg/imm32/next
10768 _Primitive-subtract-reg-from-reg:  # (payload primitive)
10769     0x11/imm32/alloc-id:fake:payload
10770     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
10771     0x11/imm32/alloc-id:fake
10772     _string-subtract/imm32/name
10773     0x11/imm32/alloc-id:fake
10774     Single-int-var-in-some-register/imm32/inouts
10775     0x11/imm32/alloc-id:fake
10776     Single-int-var-in-some-register/imm32/outputs
10777     0x11/imm32/alloc-id:fake
10778     _string_29_subtract_from/imm32/subx-name
10779     3/imm32/rm32-is-first-output
10780     1/imm32/r32-is-first-inout
10781     0/imm32/no-imm32
10782     0/imm32/no-disp32
10783     0/imm32/output-is-write-only
10784     0x11/imm32/alloc-id:fake
10785     _Primitive-subtract-reg-from-mem/imm32/next
10786 _Primitive-subtract-reg-from-mem:  # (payload primitive)
10787     0x11/imm32/alloc-id:fake:payload
10788     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
10789     0x11/imm32/alloc-id:fake
10790     _string-subtract-from/imm32/name
10791     0x11/imm32/alloc-id:fake
10792     Two-args-int-stack-int-reg/imm32/inouts
10793     0/imm32/no-outputs
10794     0/imm32/no-outputs
10795     0x11/imm32/alloc-id:fake
10796     _string_29_subtract_from/imm32/subx-name
10797     1/imm32/rm32-is-first-inout
10798     2/imm32/r32-is-second-inout
10799     0/imm32/no-imm32
10800     0/imm32/no-disp32
10801     0/imm32/output-is-write-only
10802     0x11/imm32/alloc-id:fake
10803     _Primitive-subtract-mem-from-reg/imm32/next
10804 _Primitive-subtract-mem-from-reg:  # (payload primitive)
10805     0x11/imm32/alloc-id:fake:payload
10806     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
10807     0x11/imm32/alloc-id:fake
10808     _string-subtract/imm32/name
10809     0x11/imm32/alloc-id:fake
10810     Single-int-var-in-mem/imm32/inouts
10811     0x11/imm32/alloc-id:fake
10812     Single-int-var-in-some-register/imm32/outputs
10813     0x11/imm32/alloc-id:fake
10814     _string_2b_subtract/imm32/subx-name
10815     1/imm32/rm32-is-first-inout
10816     3/imm32/r32-is-first-output
10817     0/imm32/no-imm32
10818     0/imm32/no-disp32
10819     0/imm32/output-is-write-only
10820     0x11/imm32/alloc-id:fake
10821     _Primitive-subtract-lit-from-reg/imm32/next
10822 _Primitive-subtract-lit-from-reg:  # (payload primitive)
10823     0x11/imm32/alloc-id:fake:payload
10824     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
10825     0x11/imm32/alloc-id:fake
10826     _string-subtract/imm32/name
10827     0x11/imm32/alloc-id:fake
10828     Single-lit-var/imm32/inouts
10829     0x11/imm32/alloc-id:fake
10830     Single-int-var-in-some-register/imm32/outputs
10831     0x11/imm32/alloc-id:fake
10832     _string_81_subop_subtract/imm32/subx-name
10833     3/imm32/rm32-is-first-output
10834     0/imm32/no-r32
10835     1/imm32/imm32-is-first-inout
10836     0/imm32/no-disp32
10837     0/imm32/output-is-write-only
10838     0x11/imm32/alloc-id:fake
10839     _Primitive-subtract-lit-from-mem/imm32/next
10840 _Primitive-subtract-lit-from-mem:  # (payload primitive)
10841     0x11/imm32/alloc-id:fake:payload
10842     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
10843     0x11/imm32/alloc-id:fake
10844     _string-subtract-from/imm32/name
10845     0x11/imm32/alloc-id:fake
10846     Int-var-and-literal/imm32/inouts
10847     0/imm32/no-outputs
10848     0/imm32/no-outputs
10849     0x11/imm32/alloc-id:fake
10850     _string_81_subop_subtract/imm32/subx-name
10851     1/imm32/rm32-is-first-inout
10852     0/imm32/no-r32
10853     2/imm32/imm32-is-first-inout
10854     0/imm32/no-disp32
10855     0/imm32/output-is-write-only
10856     0x11/imm32/alloc-id:fake
10857     _Primitive-and-with-eax/imm32/next
10858 # - and
10859 _Primitive-and-with-eax:  # (payload primitive)
10860     0x11/imm32/alloc-id:fake:payload
10861     # var/eax <- and lit => 25/and-with-eax lit/imm32
10862     0x11/imm32/alloc-id:fake
10863     _string-and/imm32/name
10864     0x11/imm32/alloc-id:fake
10865     Single-lit-var/imm32/inouts
10866     0x11/imm32/alloc-id:fake
10867     Single-int-var-in-eax/imm32/outputs
10868     0x11/imm32/alloc-id:fake
10869     _string_25_and_with_eax/imm32/subx-name
10870     0/imm32/no-rm32
10871     0/imm32/no-r32
10872     1/imm32/imm32-is-first-inout
10873     0/imm32/no-disp32
10874     0/imm32/output-is-write-only
10875     0x11/imm32/alloc-id:fake
10876     _Primitive-and-reg-with-reg/imm32/next
10877 _Primitive-and-reg-with-reg:  # (payload primitive)
10878     0x11/imm32/alloc-id:fake:payload
10879     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
10880     0x11/imm32/alloc-id:fake
10881     _string-and/imm32/name
10882     0x11/imm32/alloc-id:fake
10883     Single-int-var-in-some-register/imm32/inouts
10884     0x11/imm32/alloc-id:fake
10885     Single-int-var-in-some-register/imm32/outputs
10886     0x11/imm32/alloc-id:fake
10887     _string_21_and_with/imm32/subx-name
10888     3/imm32/rm32-is-first-output
10889     1/imm32/r32-is-first-inout
10890     0/imm32/no-imm32
10891     0/imm32/no-disp32
10892     0/imm32/output-is-write-only
10893     0x11/imm32/alloc-id:fake
10894     _Primitive-and-reg-with-mem/imm32/next
10895 _Primitive-and-reg-with-mem:  # (payload primitive)
10896     0x11/imm32/alloc-id:fake:payload
10897     # and-with var1 var2/reg => 21/and-with var1 var2/r32
10898     0x11/imm32/alloc-id:fake
10899     _string-and-with/imm32/name
10900     0x11/imm32/alloc-id:fake
10901     Two-args-int-stack-int-reg/imm32/inouts
10902     0/imm32/no-outputs
10903     0/imm32/no-outputs
10904     0x11/imm32/alloc-id:fake
10905     _string_21_and_with/imm32/subx-name
10906     1/imm32/rm32-is-first-inout
10907     2/imm32/r32-is-second-inout
10908     0/imm32/no-imm32
10909     0/imm32/no-disp32
10910     0/imm32/output-is-write-only
10911     0x11/imm32/alloc-id:fake
10912     _Primitive-and-mem-with-reg/imm32/next
10913 _Primitive-and-mem-with-reg:  # (payload primitive)
10914     0x11/imm32/alloc-id:fake:payload
10915     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
10916     0x11/imm32/alloc-id:fake
10917     _string-and/imm32/name
10918     0x11/imm32/alloc-id:fake
10919     Single-int-var-in-mem/imm32/inouts
10920     0x11/imm32/alloc-id:fake
10921     Single-int-var-in-some-register/imm32/outputs
10922     0x11/imm32/alloc-id:fake
10923     _string_23_and/imm32/subx-name
10924     1/imm32/rm32-is-first-inout
10925     3/imm32/r32-is-first-output
10926     0/imm32/no-imm32
10927     0/imm32/no-disp32
10928     0/imm32/output-is-write-only
10929     0x11/imm32/alloc-id:fake
10930     _Primitive-and-lit-with-reg/imm32/next
10931 _Primitive-and-lit-with-reg:  # (payload primitive)
10932     0x11/imm32/alloc-id:fake:payload
10933     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
10934     0x11/imm32/alloc-id:fake
10935     _string-and/imm32/name
10936     0x11/imm32/alloc-id:fake
10937     Single-lit-var/imm32/inouts
10938     0x11/imm32/alloc-id:fake
10939     Single-int-var-in-some-register/imm32/outputs
10940     0x11/imm32/alloc-id:fake
10941     _string_81_subop_and/imm32/subx-name
10942     3/imm32/rm32-is-first-output
10943     0/imm32/no-r32
10944     1/imm32/imm32-is-first-inout
10945     0/imm32/no-disp32
10946     0/imm32/output-is-write-only
10947     0x11/imm32/alloc-id:fake
10948     _Primitive-and-lit-with-mem/imm32/next
10949 _Primitive-and-lit-with-mem:  # (payload primitive)
10950     0x11/imm32/alloc-id:fake:payload
10951     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
10952     0x11/imm32/alloc-id:fake
10953     _string-and-with/imm32/name
10954     0x11/imm32/alloc-id:fake
10955     Int-var-and-literal/imm32/inouts
10956     0/imm32/no-outputs
10957     0/imm32/no-outputs
10958     0x11/imm32/alloc-id:fake
10959     _string_81_subop_and/imm32/subx-name
10960     1/imm32/rm32-is-first-inout
10961     0/imm32/no-r32
10962     2/imm32/imm32-is-first-inout
10963     0/imm32/no-disp32
10964     0/imm32/output-is-write-only
10965     0x11/imm32/alloc-id:fake
10966     _Primitive-or-with-eax/imm32/next
10967 # - or
10968 _Primitive-or-with-eax:  # (payload primitive)
10969     0x11/imm32/alloc-id:fake:payload
10970     # var/eax <- or lit => 0d/or-with-eax lit/imm32
10971     0x11/imm32/alloc-id:fake
10972     _string-or/imm32/name
10973     0x11/imm32/alloc-id:fake
10974     Single-lit-var/imm32/inouts
10975     0x11/imm32/alloc-id:fake
10976     Single-int-var-in-eax/imm32/outputs
10977     0x11/imm32/alloc-id:fake
10978     _string_0d_or_with_eax/imm32/subx-name
10979     0/imm32/no-rm32
10980     0/imm32/no-r32
10981     1/imm32/imm32-is-first-inout
10982     0/imm32/no-disp32
10983     0/imm32/output-is-write-only
10984     0x11/imm32/alloc-id:fake
10985     _Primitive-or-reg-with-reg/imm32/next
10986 _Primitive-or-reg-with-reg:  # (payload primitive)
10987     0x11/imm32/alloc-id:fake:payload
10988     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
10989     0x11/imm32/alloc-id:fake
10990     _string-or/imm32/name
10991     0x11/imm32/alloc-id:fake
10992     Single-int-var-in-some-register/imm32/inouts
10993     0x11/imm32/alloc-id:fake
10994     Single-int-var-in-some-register/imm32/outputs
10995     0x11/imm32/alloc-id:fake
10996     _string_09_or_with/imm32/subx-name
10997     3/imm32/rm32-is-first-output
10998     1/imm32/r32-is-first-inout
10999     0/imm32/no-imm32
11000     0/imm32/no-disp32
11001     0/imm32/output-is-write-only
11002     0x11/imm32/alloc-id:fake
11003     _Primitive-or-reg-with-mem/imm32/next
11004 _Primitive-or-reg-with-mem:  # (payload primitive)
11005     0x11/imm32/alloc-id:fake:payload
11006     # or-with var1 var2/reg => 09/or-with var1 var2/r32
11007     0x11/imm32/alloc-id:fake
11008     _string-or-with/imm32/name
11009     0x11/imm32/alloc-id:fake
11010     Two-args-int-stack-int-reg/imm32/inouts
11011     0/imm32/no-outputs
11012     0/imm32/no-outputs
11013     0x11/imm32/alloc-id:fake
11014     _string_09_or_with/imm32/subx-name
11015     1/imm32/rm32-is-first-inout
11016     2/imm32/r32-is-second-inout
11017     0/imm32/no-imm32
11018     0/imm32/no-disp32
11019     0/imm32/output-is-write-only
11020     0x11/imm32/alloc-id:fake
11021     _Primitive-or-mem-with-reg/imm32/next
11022 _Primitive-or-mem-with-reg:  # (payload primitive)
11023     0x11/imm32/alloc-id:fake:payload
11024     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
11025     0x11/imm32/alloc-id:fake
11026     _string-or/imm32/name
11027     0x11/imm32/alloc-id:fake
11028     Single-int-var-in-mem/imm32/inouts
11029     0x11/imm32/alloc-id:fake
11030     Single-int-var-in-some-register/imm32/outputs
11031     0x11/imm32/alloc-id:fake
11032     _string_0b_or/imm32/subx-name
11033     1/imm32/rm32-is-first-inout
11034     3/imm32/r32-is-first-output
11035     0/imm32/no-imm32
11036     0/imm32/no-disp32
11037     0/imm32/output-is-write-only
11038     0x11/imm32/alloc-id:fake
11039     _Primitive-or-lit-with-reg/imm32/next
11040 _Primitive-or-lit-with-reg:  # (payload primitive)
11041     0x11/imm32/alloc-id:fake:payload
11042     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
11043     0x11/imm32/alloc-id:fake
11044     _string-or/imm32/name
11045     0x11/imm32/alloc-id:fake
11046     Single-lit-var/imm32/inouts
11047     0x11/imm32/alloc-id:fake
11048     Single-int-var-in-some-register/imm32/outputs
11049     0x11/imm32/alloc-id:fake
11050     _string_81_subop_or/imm32/subx-name
11051     3/imm32/rm32-is-first-output
11052     0/imm32/no-r32
11053     1/imm32/imm32-is-first-inout
11054     0/imm32/no-disp32
11055     0/imm32/output-is-write-only
11056     0x11/imm32/alloc-id:fake
11057     _Primitive-or-lit-with-mem/imm32/next
11058 _Primitive-or-lit-with-mem:  # (payload primitive)
11059     0x11/imm32/alloc-id:fake:payload
11060     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
11061     0x11/imm32/alloc-id:fake
11062     _string-or-with/imm32/name
11063     0x11/imm32/alloc-id:fake
11064     Int-var-and-literal/imm32/inouts
11065     0/imm32/no-outputs
11066     0/imm32/no-outputs
11067     0x11/imm32/alloc-id:fake
11068     _string_81_subop_or/imm32/subx-name
11069     1/imm32/rm32-is-first-inout
11070     0/imm32/no-r32
11071     2/imm32/imm32-is-second-inout
11072     0/imm32/no-disp32
11073     0/imm32/output-is-write-only
11074     0x11/imm32/alloc-id:fake
11075     _Primitive-xor-with-eax/imm32/next
11076 # - xor
11077 _Primitive-xor-with-eax:  # (payload primitive)
11078     0x11/imm32/alloc-id:fake:payload
11079     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
11080     0x11/imm32/alloc-id:fake
11081     _string-xor/imm32/name
11082     0x11/imm32/alloc-id:fake
11083     Single-lit-var/imm32/inouts
11084     0x11/imm32/alloc-id:fake
11085     Single-int-var-in-eax/imm32/outputs
11086     0x11/imm32/alloc-id:fake
11087     _string_35_xor_with_eax/imm32/subx-name
11088     0/imm32/no-rm32
11089     0/imm32/no-r32
11090     1/imm32/imm32-is-first-inout
11091     0/imm32/no-disp32
11092     0/imm32/output-is-write-only
11093     0x11/imm32/alloc-id:fake
11094     _Primitive-xor-reg-with-reg/imm32/next
11095 _Primitive-xor-reg-with-reg:  # (payload primitive)
11096     0x11/imm32/alloc-id:fake:payload
11097     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
11098     0x11/imm32/alloc-id:fake
11099     _string-xor/imm32/name
11100     0x11/imm32/alloc-id:fake
11101     Single-int-var-in-some-register/imm32/inouts
11102     0x11/imm32/alloc-id:fake
11103     Single-int-var-in-some-register/imm32/outputs
11104     0x11/imm32/alloc-id:fake
11105     _string_31_xor_with/imm32/subx-name
11106     3/imm32/rm32-is-first-output
11107     1/imm32/r32-is-first-inout
11108     0/imm32/no-imm32
11109     0/imm32/no-disp32
11110     0/imm32/output-is-write-only
11111     0x11/imm32/alloc-id:fake
11112     _Primitive-xor-reg-with-mem/imm32/next
11113 _Primitive-xor-reg-with-mem:  # (payload primitive)
11114     0x11/imm32/alloc-id:fake:payload
11115     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
11116     0x11/imm32/alloc-id:fake
11117     _string-xor-with/imm32/name
11118     0x11/imm32/alloc-id:fake
11119     Two-args-int-stack-int-reg/imm32/inouts
11120     0/imm32/no-outputs
11121     0/imm32/no-outputs
11122     0x11/imm32/alloc-id:fake
11123     _string_31_xor_with/imm32/subx-name
11124     1/imm32/rm32-is-first-inout
11125     2/imm32/r32-is-second-inout
11126     0/imm32/no-imm32
11127     0/imm32/no-disp32
11128     0/imm32/output-is-write-only
11129     0x11/imm32/alloc-id:fake
11130     _Primitive-xor-mem-with-reg/imm32/next
11131 _Primitive-xor-mem-with-reg:  # (payload primitive)
11132     0x11/imm32/alloc-id:fake:payload
11133     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
11134     0x11/imm32/alloc-id:fake
11135     _string-xor/imm32/name
11136     0x11/imm32/alloc-id:fake
11137     Single-int-var-in-mem/imm32/inouts
11138     0x11/imm32/alloc-id:fake
11139     Single-int-var-in-some-register/imm32/outputs
11140     0x11/imm32/alloc-id:fake
11141     _string_33_xor/imm32/subx-name
11142     1/imm32/rm32-is-first-inout
11143     3/imm32/r32-is-first-output
11144     0/imm32/no-imm32
11145     0/imm32/no-disp32
11146     0/imm32/output-is-write-only
11147     0x11/imm32/alloc-id:fake
11148     _Primitive-xor-lit-with-reg/imm32/next
11149 _Primitive-xor-lit-with-reg:  # (payload primitive)
11150     0x11/imm32/alloc-id:fake:payload
11151     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
11152     0x11/imm32/alloc-id:fake
11153     _string-xor/imm32/name
11154     0x11/imm32/alloc-id:fake
11155     Single-lit-var/imm32/inouts
11156     0x11/imm32/alloc-id:fake
11157     Single-int-var-in-some-register/imm32/outputs
11158     0x11/imm32/alloc-id:fake
11159     _string_81_subop_xor/imm32/subx-name
11160     3/imm32/rm32-is-first-output
11161     0/imm32/no-r32
11162     1/imm32/imm32-is-first-inout
11163     0/imm32/no-disp32
11164     0/imm32/output-is-write-only
11165     0x11/imm32/alloc-id:fake
11166     _Primitive-xor-lit-with-mem/imm32/next
11167 _Primitive-xor-lit-with-mem:  # (payload primitive)
11168     0x11/imm32/alloc-id:fake:payload
11169     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
11170     0x11/imm32/alloc-id:fake
11171     _string-xor-with/imm32/name
11172     0x11/imm32/alloc-id:fake
11173     Int-var-and-literal/imm32/inouts
11174     0/imm32/no-outputs
11175     0/imm32/no-outputs
11176     0x11/imm32/alloc-id:fake
11177     _string_81_subop_xor/imm32/subx-name
11178     1/imm32/rm32-is-first-inout
11179     0/imm32/no-r32
11180     2/imm32/imm32-is-first-inout
11181     0/imm32/no-disp32
11182     0/imm32/output-is-write-only
11183     0x11/imm32/alloc-id:fake
11184     _Primitive-copy-to-eax/imm32/next
11185 # - copy
11186 _Primitive-copy-to-eax:  # (payload primitive)
11187     0x11/imm32/alloc-id:fake:payload
11188     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
11189     0x11/imm32/alloc-id:fake
11190     _string-copy/imm32/name
11191     0x11/imm32/alloc-id:fake
11192     Single-lit-var/imm32/inouts
11193     0x11/imm32/alloc-id:fake
11194     Single-int-var-in-eax/imm32/outputs
11195     0x11/imm32/alloc-id:fake
11196     _string_b8_copy_to_eax/imm32/subx-name
11197     0/imm32/no-rm32
11198     0/imm32/no-r32
11199     1/imm32/imm32-is-first-inout
11200     0/imm32/no-disp32
11201     1/imm32/output-is-write-only
11202     0x11/imm32/alloc-id:fake
11203     _Primitive-copy-to-ecx/imm32/next
11204 _Primitive-copy-to-ecx:  # (payload primitive)
11205     0x11/imm32/alloc-id:fake:payload
11206     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
11207     0x11/imm32/alloc-id:fake
11208     _string-copy/imm32/name
11209     0x11/imm32/alloc-id:fake
11210     Single-lit-var/imm32/inouts
11211     0x11/imm32/alloc-id:fake
11212     Single-int-var-in-ecx/imm32/outputs
11213     0x11/imm32/alloc-id:fake
11214     _string_b9_copy_to_ecx/imm32/subx-name
11215     0/imm32/no-rm32
11216     0/imm32/no-r32
11217     1/imm32/imm32-is-first-inout
11218     0/imm32/no-disp32
11219     1/imm32/output-is-write-only
11220     0x11/imm32/alloc-id:fake
11221     _Primitive-copy-to-edx/imm32/next
11222 _Primitive-copy-to-edx:  # (payload primitive)
11223     0x11/imm32/alloc-id:fake:payload
11224     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
11225     0x11/imm32/alloc-id:fake
11226     _string-copy/imm32/name
11227     0x11/imm32/alloc-id:fake
11228     Single-lit-var/imm32/inouts
11229     0x11/imm32/alloc-id:fake
11230     Single-int-var-in-edx/imm32/outputs
11231     0x11/imm32/alloc-id:fake
11232     _string_ba_copy_to_edx/imm32/subx-name
11233     0/imm32/no-rm32
11234     0/imm32/no-r32
11235     1/imm32/imm32-is-first-inout
11236     0/imm32/no-disp32
11237     1/imm32/output-is-write-only
11238     0x11/imm32/alloc-id:fake
11239     _Primitive-copy-to-ebx/imm32/next
11240 _Primitive-copy-to-ebx:  # (payload primitive)
11241     0x11/imm32/alloc-id:fake:payload
11242     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
11243     0x11/imm32/alloc-id:fake
11244     _string-copy/imm32/name
11245     0x11/imm32/alloc-id:fake
11246     Single-lit-var/imm32/inouts
11247     0x11/imm32/alloc-id:fake
11248     Single-int-var-in-ebx/imm32/outputs
11249     0x11/imm32/alloc-id:fake
11250     _string_bb_copy_to_ebx/imm32/subx-name
11251     0/imm32/no-rm32
11252     0/imm32/no-r32
11253     1/imm32/imm32-is-first-inout
11254     0/imm32/no-disp32
11255     1/imm32/output-is-write-only
11256     0x11/imm32/alloc-id:fake
11257     _Primitive-copy-to-esi/imm32/next
11258 _Primitive-copy-to-esi:  # (payload primitive)
11259     0x11/imm32/alloc-id:fake:payload
11260     # var/esi <- copy lit => be/copy-to-esi lit/imm32
11261     0x11/imm32/alloc-id:fake
11262     _string-copy/imm32/name
11263     0x11/imm32/alloc-id:fake
11264     Single-lit-var/imm32/inouts
11265     0x11/imm32/alloc-id:fake
11266     Single-int-var-in-esi/imm32/outputs
11267     0x11/imm32/alloc-id:fake
11268     _string_be_copy_to_esi/imm32/subx-name
11269     0/imm32/no-rm32
11270     0/imm32/no-r32
11271     1/imm32/imm32-is-first-inout
11272     0/imm32/no-disp32
11273     1/imm32/output-is-write-only
11274     0x11/imm32/alloc-id:fake
11275     _Primitive-copy-to-edi/imm32/next
11276 _Primitive-copy-to-edi:  # (payload primitive)
11277     0x11/imm32/alloc-id:fake:payload
11278     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
11279     0x11/imm32/alloc-id:fake
11280     _string-copy/imm32/name
11281     0x11/imm32/alloc-id:fake
11282     Single-lit-var/imm32/inouts
11283     0x11/imm32/alloc-id:fake
11284     Single-int-var-in-edi/imm32/outputs
11285     0x11/imm32/alloc-id:fake
11286     _string_bf_copy_to_edi/imm32/subx-name
11287     0/imm32/no-rm32
11288     0/imm32/no-r32
11289     1/imm32/imm32-is-first-inout
11290     0/imm32/no-disp32
11291     1/imm32/output-is-write-only
11292     0x11/imm32/alloc-id:fake
11293     _Primitive-copy-reg-to-reg/imm32/next
11294 _Primitive-copy-reg-to-reg:  # (payload primitive)
11295     0x11/imm32/alloc-id:fake:payload
11296     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
11297     0x11/imm32/alloc-id:fake
11298     _string-copy/imm32/name
11299     0x11/imm32/alloc-id:fake
11300     Single-int-var-in-some-register/imm32/inouts
11301     0x11/imm32/alloc-id:fake
11302     Single-int-var-in-some-register/imm32/outputs
11303     0x11/imm32/alloc-id:fake
11304     _string_89_<-/imm32/subx-name
11305     3/imm32/rm32-is-first-output
11306     1/imm32/r32-is-first-inout
11307     0/imm32/no-imm32
11308     0/imm32/no-disp32
11309     1/imm32/output-is-write-only
11310     0x11/imm32/alloc-id:fake
11311     _Primitive-copy-reg-to-mem/imm32/next
11312 _Primitive-copy-reg-to-mem:  # (payload primitive)
11313     0x11/imm32/alloc-id:fake:payload
11314     # copy-to var1 var2/reg => 89/<- var1 var2/r32
11315     0x11/imm32/alloc-id:fake
11316     _string-copy-to/imm32/name
11317     0x11/imm32/alloc-id:fake
11318     Two-args-int-stack-int-reg/imm32/inouts
11319     0/imm32/no-outputs
11320     0/imm32/no-outputs
11321     0x11/imm32/alloc-id:fake
11322     _string_89_<-/imm32/subx-name
11323     1/imm32/rm32-is-first-inout
11324     2/imm32/r32-is-second-inout
11325     0/imm32/no-imm32
11326     0/imm32/no-disp32
11327     1/imm32/output-is-write-only
11328     0x11/imm32/alloc-id:fake
11329     _Primitive-copy-mem-to-reg/imm32/next
11330 _Primitive-copy-mem-to-reg:  # (payload primitive)
11331     0x11/imm32/alloc-id:fake:payload
11332     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
11333     0x11/imm32/alloc-id:fake
11334     _string-copy/imm32/name
11335     0x11/imm32/alloc-id:fake
11336     Single-int-var-in-mem/imm32/inouts
11337     0x11/imm32/alloc-id:fake
11338     Single-int-var-in-some-register/imm32/outputs
11339     0x11/imm32/alloc-id:fake
11340     _string_8b_->/imm32/subx-name
11341     1/imm32/rm32-is-first-inout
11342     3/imm32/r32-is-first-output
11343     0/imm32/no-imm32
11344     0/imm32/no-disp32
11345     1/imm32/output-is-write-only
11346     0x11/imm32/alloc-id:fake
11347     _Primitive-copy-lit-to-reg/imm32/next
11348 _Primitive-copy-lit-to-reg:  # (payload primitive)
11349     0x11/imm32/alloc-id:fake:payload
11350     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
11351     0x11/imm32/alloc-id:fake
11352     _string-copy/imm32/name
11353     0x11/imm32/alloc-id:fake
11354     Single-lit-var/imm32/inouts
11355     0x11/imm32/alloc-id:fake
11356     Single-int-var-in-some-register/imm32/outputs
11357     0x11/imm32/alloc-id:fake
11358     _string_c7_subop_copy/imm32/subx-name
11359     3/imm32/rm32-is-first-output
11360     0/imm32/no-r32
11361     1/imm32/imm32-is-first-inout
11362     0/imm32/no-disp32
11363     1/imm32/output-is-write-only
11364     0x11/imm32/alloc-id:fake
11365     _Primitive-copy-lit-to-mem/imm32/next
11366 _Primitive-copy-lit-to-mem:  # (payload primitive)
11367     0x11/imm32/alloc-id:fake:payload
11368     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
11369     0x11/imm32/alloc-id:fake
11370     _string-copy-to/imm32/name
11371     0x11/imm32/alloc-id:fake
11372     Int-var-and-literal/imm32/inouts
11373     0/imm32/no-outputs
11374     0/imm32/no-outputs
11375     0x11/imm32/alloc-id:fake
11376     _string_c7_subop_copy/imm32/subx-name
11377     1/imm32/rm32-is-first-inout
11378     0/imm32/no-r32
11379     2/imm32/imm32-is-first-inout
11380     0/imm32/no-disp32
11381     1/imm32/output-is-write-only
11382     0x11/imm32/alloc-id:fake
11383     _Primitive-address/imm32/next
11384 # - address
11385 _Primitive-address:  # (payload primitive)
11386     0x11/imm32/alloc-id:fake:payload
11387     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
11388     0x11/imm32/alloc-id:fake
11389     _string-address/imm32/name
11390     0x11/imm32/alloc-id:fake
11391     Single-int-var-in-mem/imm32/inouts
11392     0x11/imm32/alloc-id:fake
11393     Single-addr-var-in-some-register/imm32/outputs
11394     0x11/imm32/alloc-id:fake
11395     _string_8d_copy_address/imm32/subx-name
11396     1/imm32/rm32-is-first-inout
11397     3/imm32/r32-is-first-output
11398     0/imm32/no-imm32
11399     0/imm32/no-disp32
11400     1/imm32/output-is-write-only
11401     0x11/imm32/alloc-id:fake
11402     _Primitive-compare-mem-with-reg/imm32/next
11403 # - compare
11404 _Primitive-compare-mem-with-reg:  # (payload primitive)
11405     0x11/imm32/alloc-id:fake:payload
11406     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
11407     0x11/imm32/alloc-id:fake
11408     _string-compare/imm32/name
11409     0x11/imm32/alloc-id:fake
11410     Two-args-int-stack-int-reg/imm32/inouts
11411     0/imm32/no-outputs
11412     0/imm32/no-outputs
11413     0x11/imm32/alloc-id:fake
11414     _string_39_compare->/imm32/subx-name
11415     1/imm32/rm32-is-first-inout
11416     2/imm32/r32-is-second-inout
11417     0/imm32/no-imm32
11418     0/imm32/no-disp32
11419     0/imm32/output-is-write-only
11420     0x11/imm32/alloc-id:fake
11421     _Primitive-compare-reg-with-mem/imm32/next
11422 _Primitive-compare-reg-with-mem:  # (payload primitive)
11423     0x11/imm32/alloc-id:fake:payload
11424     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
11425     0x11/imm32/alloc-id:fake
11426     _string-compare/imm32/name
11427     0x11/imm32/alloc-id:fake
11428     Two-args-int-reg-int-stack/imm32/inouts
11429     0/imm32/no-outputs
11430     0/imm32/no-outputs
11431     0x11/imm32/alloc-id:fake
11432     _string_3b_compare<-/imm32/subx-name
11433     2/imm32/rm32-is-second-inout
11434     1/imm32/r32-is-first-inout
11435     0/imm32/no-imm32
11436     0/imm32/no-disp32
11437     0/imm32/output-is-write-only
11438     0x11/imm32/alloc-id:fake
11439     _Primitive-compare-eax-with-literal/imm32/next
11440 _Primitive-compare-eax-with-literal:  # (payload primitive)
11441     0x11/imm32/alloc-id:fake:payload
11442     # compare var1/eax n => 3d/compare-eax-with n/imm32
11443     0x11/imm32/alloc-id:fake
11444     _string-compare/imm32/name
11445     0x11/imm32/alloc-id:fake
11446     Two-args-int-eax-int-literal/imm32/inouts
11447     0/imm32/no-outputs
11448     0/imm32/no-outputs
11449     0x11/imm32/alloc-id:fake
11450     _string_3d_compare_eax_with/imm32/subx-name
11451     0/imm32/no-rm32
11452     0/imm32/no-r32
11453     2/imm32/imm32-is-second-inout
11454     0/imm32/no-disp32
11455     0/imm32/output-is-write-only
11456     0x11/imm32/alloc-id:fake
11457     _Primitive-compare-reg-with-literal/imm32/next
11458 _Primitive-compare-reg-with-literal:  # (payload primitive)
11459     0x11/imm32/alloc-id:fake:payload
11460     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
11461     0x11/imm32/alloc-id:fake
11462     _string-compare/imm32/name
11463     0x11/imm32/alloc-id:fake
11464     Int-var-in-register-and-literal/imm32/inouts
11465     0/imm32/no-outputs
11466     0/imm32/no-outputs
11467     0x11/imm32/alloc-id:fake
11468     _string_81_subop_compare/imm32/subx-name
11469     1/imm32/rm32-is-first-inout
11470     0/imm32/no-r32
11471     2/imm32/imm32-is-second-inout
11472     0/imm32/no-disp32
11473     0/imm32/output-is-write-only
11474     0x11/imm32/alloc-id:fake
11475     _Primitive-compare-mem-with-literal/imm32/next
11476 _Primitive-compare-mem-with-literal:  # (payload primitive)
11477     0x11/imm32/alloc-id:fake:payload
11478     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
11479     0x11/imm32/alloc-id:fake
11480     _string-compare/imm32/name
11481     0x11/imm32/alloc-id:fake
11482     Int-var-and-literal/imm32/inouts
11483     0/imm32/no-outputs
11484     0/imm32/no-outputs
11485     0x11/imm32/alloc-id:fake
11486     _string_81_subop_compare/imm32/subx-name
11487     1/imm32/rm32-is-first-inout
11488     0/imm32/no-r32
11489     2/imm32/imm32-is-second-inout
11490     0/imm32/no-disp32
11491     0/imm32/output-is-write-only
11492     0x11/imm32/alloc-id:fake
11493     _Primitive-multiply-reg-by-mem/imm32/next
11494 # - multiply
11495 _Primitive-multiply-reg-by-mem:  # (payload primitive)
11496     0x11/imm32/alloc-id:fake:payload
11497     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
11498     0x11/imm32/alloc-id:fake
11499     _string-multiply/imm32/name
11500     0x11/imm32/alloc-id:fake
11501     Single-int-var-in-mem/imm32/inouts
11502     0x11/imm32/alloc-id:fake
11503     Single-int-var-in-some-register/imm32/outputs
11504     0x11/imm32/alloc-id:fake
11505     _string_0f_af_multiply/imm32/subx-name
11506     1/imm32/rm32-is-first-inout
11507     3/imm32/r32-is-first-output
11508     0/imm32/no-imm32
11509     0/imm32/no-disp32
11510     0/imm32/output-is-write-only
11511     0x11/imm32/alloc-id:fake
11512     _Primitive-break-if-addr</imm32/next
11513 # - branches
11514 _Primitive-break-if-addr<:  # (payload primitive)
11515     0x11/imm32/alloc-id:fake:payload
11516     0x11/imm32/alloc-id:fake
11517     _string-break-if-addr</imm32/name
11518     0/imm32/no-inouts
11519     0/imm32/no-inouts
11520     0/imm32/no-outputs
11521     0/imm32/no-outputs
11522     0x11/imm32/alloc-id:fake
11523     _string_0f_82_jump_break/imm32/subx-name
11524     0/imm32/no-rm32
11525     0/imm32/no-r32
11526     0/imm32/no-imm32
11527     0/imm32/no-disp32
11528     0/imm32/no-output
11529     0x11/imm32/alloc-id:fake
11530     _Primitive-break-if-addr>=/imm32/next
11531 _Primitive-break-if-addr>=:  # (payload primitive)
11532     0x11/imm32/alloc-id:fake:payload
11533     0x11/imm32/alloc-id:fake
11534     _string-break-if-addr>=/imm32/name
11535     0/imm32/no-inouts
11536     0/imm32/no-inouts
11537     0/imm32/no-outputs
11538     0/imm32/no-outputs
11539     0x11/imm32/alloc-id:fake
11540     _string_0f_83_jump_break/imm32/subx-name
11541     0/imm32/no-rm32
11542     0/imm32/no-r32
11543     0/imm32/no-imm32
11544     0/imm32/no-disp32
11545     0/imm32/no-output
11546     0x11/imm32/alloc-id:fake
11547     _Primitive-break-if-=/imm32/next
11548 _Primitive-break-if-=:  # (payload primitive)
11549     0x11/imm32/alloc-id:fake:payload
11550     0x11/imm32/alloc-id:fake
11551     _string-break-if-=/imm32/name
11552     0/imm32/no-inouts
11553     0/imm32/no-inouts
11554     0/imm32/no-outputs
11555     0/imm32/no-outputs
11556     0x11/imm32/alloc-id:fake
11557     _string_0f_84_jump_break/imm32/subx-name
11558     0/imm32/no-rm32
11559     0/imm32/no-r32
11560     0/imm32/no-imm32
11561     0/imm32/no-disp32
11562     0/imm32/no-output
11563     0x11/imm32/alloc-id:fake
11564     _Primitive-break-if-!=/imm32/next
11565 _Primitive-break-if-!=:  # (payload primitive)
11566     0x11/imm32/alloc-id:fake:payload
11567     0x11/imm32/alloc-id:fake
11568     _string-break-if-!=/imm32/name
11569     0/imm32/no-inouts
11570     0/imm32/no-inouts
11571     0/imm32/no-outputs
11572     0/imm32/no-outputs
11573     0x11/imm32/alloc-id:fake
11574     _string_0f_85_jump_break/imm32/subx-name
11575     0/imm32/no-rm32
11576     0/imm32/no-r32
11577     0/imm32/no-imm32
11578     0/imm32/no-disp32
11579     0/imm32/no-output
11580     0x11/imm32/alloc-id:fake
11581     _Primitive-break-if-addr<=/imm32/next
11582 _Primitive-break-if-addr<=:  # (payload primitive)
11583     0x11/imm32/alloc-id:fake:payload
11584     0x11/imm32/alloc-id:fake
11585     _string-break-if-addr<=/imm32/name
11586     0/imm32/no-inouts
11587     0/imm32/no-inouts
11588     0/imm32/no-outputs
11589     0/imm32/no-outputs
11590     0x11/imm32/alloc-id:fake
11591     _string_0f_86_jump_break/imm32/subx-name
11592     0/imm32/no-rm32
11593     0/imm32/no-r32
11594     0/imm32/no-imm32
11595     0/imm32/no-disp32
11596     0/imm32/no-output
11597     0x11/imm32/alloc-id:fake
11598     _Primitive-break-if-addr>/imm32/next
11599 _Primitive-break-if-addr>:  # (payload primitive)
11600     0x11/imm32/alloc-id:fake:payload
11601     0x11/imm32/alloc-id:fake
11602     _string-break-if-addr>/imm32/name
11603     0/imm32/no-inouts
11604     0/imm32/no-inouts
11605     0/imm32/no-outputs
11606     0/imm32/no-outputs
11607     0x11/imm32/alloc-id:fake
11608     _string_0f_87_jump_break/imm32/subx-name
11609     0/imm32/no-rm32
11610     0/imm32/no-r32
11611     0/imm32/no-imm32
11612     0/imm32/no-disp32
11613     0/imm32/no-output
11614     0x11/imm32/alloc-id:fake
11615     _Primitive-break-if-</imm32/next
11616 _Primitive-break-if-<:  # (payload primitive)
11617     0x11/imm32/alloc-id:fake:payload
11618     0x11/imm32/alloc-id:fake
11619     _string-break-if-</imm32/name
11620     0/imm32/no-inouts
11621     0/imm32/no-inouts
11622     0/imm32/no-outputs
11623     0/imm32/no-outputs
11624     0x11/imm32/alloc-id:fake
11625     _string_0f_8c_jump_break/imm32/subx-name
11626     0/imm32/no-rm32
11627     0/imm32/no-r32
11628     0/imm32/no-imm32
11629     0/imm32/no-disp32
11630     0/imm32/no-output
11631     0x11/imm32/alloc-id:fake
11632     _Primitive-break-if->=/imm32/next
11633 _Primitive-break-if->=:  # (payload primitive)
11634     0x11/imm32/alloc-id:fake:payload
11635     0x11/imm32/alloc-id:fake
11636     _string-break-if->=/imm32/name
11637     0/imm32/no-inouts
11638     0/imm32/no-inouts
11639     0/imm32/no-outputs
11640     0/imm32/no-outputs
11641     0x11/imm32/alloc-id:fake
11642     _string_0f_8d_jump_break/imm32/subx-name
11643     0/imm32/no-rm32
11644     0/imm32/no-r32
11645     0/imm32/no-imm32
11646     0/imm32/no-disp32
11647     0/imm32/no-output
11648     0x11/imm32/alloc-id:fake
11649     _Primitive-break-if-<=/imm32/next
11650 _Primitive-break-if-<=:  # (payload primitive)
11651     0x11/imm32/alloc-id:fake:payload
11652     0x11/imm32/alloc-id:fake
11653     _string-break-if-<=/imm32/name
11654     0/imm32/no-inouts
11655     0/imm32/no-inouts
11656     0/imm32/no-outputs
11657     0/imm32/no-outputs
11658     0x11/imm32/alloc-id:fake
11659     _string_0f_8e_jump_break/imm32/subx-name
11660     0/imm32/no-rm32
11661     0/imm32/no-r32
11662     0/imm32/no-imm32
11663     0/imm32/no-disp32
11664     0/imm32/no-output
11665     0x11/imm32/alloc-id:fake
11666     _Primitive-break-if->/imm32/next
11667 _Primitive-break-if->:  # (payload primitive)
11668     0x11/imm32/alloc-id:fake:payload
11669     0x11/imm32/alloc-id:fake
11670     _string-break-if->/imm32/name
11671     0/imm32/no-inouts
11672     0/imm32/no-inouts
11673     0/imm32/no-outputs
11674     0/imm32/no-outputs
11675     0x11/imm32/alloc-id:fake
11676     _string_0f_8f_jump_break/imm32/subx-name
11677     0/imm32/no-rm32
11678     0/imm32/no-r32
11679     0/imm32/no-imm32
11680     0/imm32/no-disp32
11681     0/imm32/no-output
11682     0x11/imm32/alloc-id:fake
11683     _Primitive-break/imm32/next
11684 _Primitive-break:  # (payload primitive)
11685     0x11/imm32/alloc-id:fake:payload
11686     0x11/imm32/alloc-id:fake
11687     _string-break/imm32/name
11688     0/imm32/no-inouts
11689     0/imm32/no-inouts
11690     0/imm32/no-outputs
11691     0/imm32/no-outputs
11692     0x11/imm32/alloc-id:fake
11693     _string_e9_jump_break/imm32/subx-name
11694     0/imm32/no-rm32
11695     0/imm32/no-r32
11696     0/imm32/no-imm32
11697     0/imm32/no-disp32
11698     0/imm32/no-output
11699     0x11/imm32/alloc-id:fake
11700     _Primitive-loop-if-addr</imm32/next
11701 _Primitive-loop-if-addr<:  # (payload primitive)
11702     0x11/imm32/alloc-id:fake:payload
11703     0x11/imm32/alloc-id:fake
11704     _string-loop-if-addr</imm32/name
11705     0/imm32/no-inouts
11706     0/imm32/no-inouts
11707     0/imm32/no-outputs
11708     0/imm32/no-outputs
11709     0x11/imm32/alloc-id:fake
11710     _string_0f_82_jump_loop/imm32/subx-name
11711     0/imm32/no-rm32
11712     0/imm32/no-r32
11713     0/imm32/no-imm32
11714     0/imm32/no-disp32
11715     0/imm32/no-output
11716     0x11/imm32/alloc-id:fake
11717     _Primitive-loop-if-addr>=/imm32/next
11718 _Primitive-loop-if-addr>=:  # (payload primitive)
11719     0x11/imm32/alloc-id:fake:payload
11720     0x11/imm32/alloc-id:fake
11721     _string-loop-if-addr>=/imm32/name
11722     0/imm32/no-inouts
11723     0/imm32/no-inouts
11724     0/imm32/no-outputs
11725     0/imm32/no-outputs
11726     0x11/imm32/alloc-id:fake
11727     _string_0f_83_jump_loop/imm32/subx-name
11728     0/imm32/no-rm32
11729     0/imm32/no-r32
11730     0/imm32/no-imm32
11731     0/imm32/no-disp32
11732     0/imm32/no-output
11733     0x11/imm32/alloc-id:fake
11734     _Primitive-loop-if-=/imm32/next
11735 _Primitive-loop-if-=:  # (payload primitive)
11736     0x11/imm32/alloc-id:fake:payload
11737     0x11/imm32/alloc-id:fake
11738     _string-loop-if-=/imm32/name
11739     0/imm32/no-inouts
11740     0/imm32/no-inouts
11741     0/imm32/no-outputs
11742     0/imm32/no-outputs
11743     0x11/imm32/alloc-id:fake
11744     _string_0f_84_jump_loop/imm32/subx-name
11745     0/imm32/no-rm32
11746     0/imm32/no-r32
11747     0/imm32/no-imm32
11748     0/imm32/no-disp32
11749     0/imm32/no-output
11750     0x11/imm32/alloc-id:fake
11751     _Primitive-loop-if-!=/imm32/next
11752 _Primitive-loop-if-!=:  # (payload primitive)
11753     0x11/imm32/alloc-id:fake:payload
11754     0x11/imm32/alloc-id:fake
11755     _string-loop-if-!=/imm32/name
11756     0/imm32/no-inouts
11757     0/imm32/no-inouts
11758     0/imm32/no-outputs
11759     0/imm32/no-outputs
11760     0x11/imm32/alloc-id:fake
11761     _string_0f_85_jump_loop/imm32/subx-name
11762     0/imm32/no-rm32
11763     0/imm32/no-r32
11764     0/imm32/no-imm32
11765     0/imm32/no-disp32
11766     0/imm32/no-output
11767     0x11/imm32/alloc-id:fake
11768     _Primitive-loop-if-addr<=/imm32/next
11769 _Primitive-loop-if-addr<=:  # (payload primitive)
11770     0x11/imm32/alloc-id:fake:payload
11771     0x11/imm32/alloc-id:fake
11772     _string-loop-if-addr<=/imm32/name
11773     0/imm32/no-inouts
11774     0/imm32/no-inouts
11775     0/imm32/no-outputs
11776     0/imm32/no-outputs
11777     0x11/imm32/alloc-id:fake
11778     _string_0f_86_jump_loop/imm32/subx-name
11779     0/imm32/no-rm32
11780     0/imm32/no-r32
11781     0/imm32/no-imm32
11782     0/imm32/no-disp32
11783     0/imm32/no-output
11784     0x11/imm32/alloc-id:fake
11785     _Primitive-loop-if-addr>/imm32/next
11786 _Primitive-loop-if-addr>:  # (payload primitive)
11787     0x11/imm32/alloc-id:fake:payload
11788     0x11/imm32/alloc-id:fake
11789     _string-loop-if-addr>/imm32/name
11790     0/imm32/no-inouts
11791     0/imm32/no-inouts
11792     0/imm32/no-outputs
11793     0/imm32/no-outputs
11794     0x11/imm32/alloc-id:fake
11795     _string_0f_87_jump_loop/imm32/subx-name
11796     0/imm32/no-rm32
11797     0/imm32/no-r32
11798     0/imm32/no-imm32
11799     0/imm32/no-disp32
11800     0/imm32/no-output
11801     0x11/imm32/alloc-id:fake
11802     _Primitive-loop-if-</imm32/next
11803 _Primitive-loop-if-<:  # (payload primitive)
11804     0x11/imm32/alloc-id:fake:payload
11805     0x11/imm32/alloc-id:fake
11806     _string-loop-if-</imm32/name
11807     0/imm32/no-inouts
11808     0/imm32/no-inouts
11809     0/imm32/no-outputs
11810     0/imm32/no-outputs
11811     0x11/imm32/alloc-id:fake
11812     _string_0f_8c_jump_loop/imm32/subx-name
11813     0/imm32/no-rm32
11814     0/imm32/no-r32
11815     0/imm32/no-imm32
11816     0/imm32/no-disp32
11817     0/imm32/no-output
11818     0x11/imm32/alloc-id:fake
11819     _Primitive-loop-if->=/imm32/next
11820 _Primitive-loop-if->=:  # (payload primitive)
11821     0x11/imm32/alloc-id:fake:payload
11822     0x11/imm32/alloc-id:fake
11823     _string-loop-if->=/imm32/name
11824     0/imm32/no-inouts
11825     0/imm32/no-inouts
11826     0/imm32/no-outputs
11827     0/imm32/no-outputs
11828     0x11/imm32/alloc-id:fake
11829     _string_0f_8d_jump_loop/imm32/subx-name
11830     0/imm32/no-rm32
11831     0/imm32/no-r32
11832     0/imm32/no-imm32
11833     0/imm32/no-disp32
11834     0/imm32/no-output
11835     0x11/imm32/alloc-id:fake
11836     _Primitive-loop-if-<=/imm32/next
11837 _Primitive-loop-if-<=:  # (payload primitive)
11838     0x11/imm32/alloc-id:fake:payload
11839     0x11/imm32/alloc-id:fake
11840     _string-loop-if-<=/imm32/name
11841     0/imm32/no-inouts
11842     0/imm32/no-inouts
11843     0/imm32/no-outputs
11844     0/imm32/no-outputs
11845     0x11/imm32/alloc-id:fake
11846     _string_0f_8e_jump_loop/imm32/subx-name
11847     0/imm32/no-rm32
11848     0/imm32/no-r32
11849     0/imm32/no-imm32
11850     0/imm32/no-disp32
11851     0/imm32/no-output
11852     0x11/imm32/alloc-id:fake
11853     _Primitive-loop-if->/imm32/next
11854 _Primitive-loop-if->:  # (payload primitive)
11855     0x11/imm32/alloc-id:fake:payload
11856     0x11/imm32/alloc-id:fake
11857     _string-loop-if->/imm32/name
11858     0/imm32/no-inouts
11859     0/imm32/no-inouts
11860     0/imm32/no-outputs
11861     0/imm32/no-outputs
11862     0x11/imm32/alloc-id:fake
11863     _string_0f_8f_jump_loop/imm32/subx-name
11864     0/imm32/no-rm32
11865     0/imm32/no-r32
11866     0/imm32/no-imm32
11867     0/imm32/no-disp32
11868     0/imm32/no-output
11869     0x11/imm32/alloc-id:fake
11870     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
11871 _Primitive-loop:  # (payload primitive)
11872     0x11/imm32/alloc-id:fake:payload
11873     0x11/imm32/alloc-id:fake
11874     _string-loop/imm32/name
11875     0/imm32/no-inouts
11876     0/imm32/no-inouts
11877     0/imm32/no-outputs
11878     0/imm32/no-outputs
11879     0x11/imm32/alloc-id:fake
11880     _string_e9_jump_loop/imm32/subx-name
11881     0/imm32/no-rm32
11882     0/imm32/no-r32
11883     0/imm32/no-imm32
11884     0/imm32/no-disp32
11885     0/imm32/no-output
11886     0x11/imm32/alloc-id:fake
11887     _Primitive-break-if-addr<-named/imm32/next
11888 # - branches to named blocks
11889 _Primitive-break-if-addr<-named:  # (payload primitive)
11890     0x11/imm32/alloc-id:fake:payload
11891     0x11/imm32/alloc-id:fake
11892     _string-break-if-addr</imm32/name
11893     0x11/imm32/alloc-id:fake
11894     Single-lit-var/imm32/inouts
11895     0/imm32/no-outputs
11896     0/imm32/no-outputs
11897     0x11/imm32/alloc-id:fake
11898     _string_0f_82_jump_label/imm32/subx-name
11899     0/imm32/no-rm32
11900     0/imm32/no-r32
11901     0/imm32/no-imm32
11902     1/imm32/disp32-is-first-inout
11903     0/imm32/no-output
11904     0x11/imm32/alloc-id:fake
11905     _Primitive-break-if-addr>=-named/imm32/next
11906 _Primitive-break-if-addr>=-named:  # (payload primitive)
11907     0x11/imm32/alloc-id:fake:payload
11908     0x11/imm32/alloc-id:fake
11909     _string-break-if-addr>=/imm32/name
11910     0x11/imm32/alloc-id:fake
11911     Single-lit-var/imm32/inouts
11912     0/imm32/no-outputs
11913     0/imm32/no-outputs
11914     0x11/imm32/alloc-id:fake
11915     _string_0f_83_jump_label/imm32/subx-name
11916     0/imm32/no-rm32
11917     0/imm32/no-r32
11918     0/imm32/no-imm32
11919     1/imm32/disp32-is-first-inout
11920     0/imm32/no-output
11921     0x11/imm32/alloc-id:fake
11922     _Primitive-break-if-=-named/imm32/next
11923 _Primitive-break-if-=-named:  # (payload primitive)
11924     0x11/imm32/alloc-id:fake:payload
11925     0x11/imm32/alloc-id:fake
11926     _string-break-if-=/imm32/name
11927     0x11/imm32/alloc-id:fake
11928     Single-lit-var/imm32/inouts
11929     0/imm32/no-outputs
11930     0/imm32/no-outputs
11931     0x11/imm32/alloc-id:fake
11932     _string_0f_84_jump_label/imm32/subx-name
11933     0/imm32/no-rm32
11934     0/imm32/no-r32
11935     0/imm32/no-imm32
11936     1/imm32/disp32-is-first-inout
11937     0/imm32/no-output
11938     0x11/imm32/alloc-id:fake
11939     _Primitive-break-if-!=-named/imm32/next
11940 _Primitive-break-if-!=-named:  # (payload primitive)
11941     0x11/imm32/alloc-id:fake:payload
11942     0x11/imm32/alloc-id:fake
11943     _string-break-if-!=/imm32/name
11944     0x11/imm32/alloc-id:fake
11945     Single-lit-var/imm32/inouts
11946     0/imm32/no-outputs
11947     0/imm32/no-outputs
11948     0x11/imm32/alloc-id:fake
11949     _string_0f_85_jump_label/imm32/subx-name
11950     0/imm32/no-rm32
11951     0/imm32/no-r32
11952     0/imm32/no-imm32
11953     1/imm32/disp32-is-first-inout
11954     0/imm32/no-output
11955     0x11/imm32/alloc-id:fake
11956     _Primitive-break-if-addr<=-named/imm32/next
11957 _Primitive-break-if-addr<=-named:  # (payload primitive)
11958     0x11/imm32/alloc-id:fake:payload
11959     0x11/imm32/alloc-id:fake
11960     _string-break-if-addr<=/imm32/name
11961     0x11/imm32/alloc-id:fake
11962     Single-lit-var/imm32/inouts
11963     0/imm32/no-outputs
11964     0/imm32/no-outputs
11965     0x11/imm32/alloc-id:fake
11966     _string_0f_86_jump_label/imm32/subx-name
11967     0/imm32/no-rm32
11968     0/imm32/no-r32
11969     0/imm32/no-imm32
11970     1/imm32/disp32-is-first-inout
11971     0/imm32/no-output
11972     0x11/imm32/alloc-id:fake
11973     _Primitive-break-if-addr>-named/imm32/next
11974 _Primitive-break-if-addr>-named:  # (payload primitive)
11975     0x11/imm32/alloc-id:fake:payload
11976     0x11/imm32/alloc-id:fake
11977     _string-break-if-addr>/imm32/name
11978     0x11/imm32/alloc-id:fake
11979     Single-lit-var/imm32/inouts
11980     0/imm32/no-outputs
11981     0/imm32/no-outputs
11982     0x11/imm32/alloc-id:fake
11983     _string_0f_87_jump_label/imm32/subx-name
11984     0/imm32/no-rm32
11985     0/imm32/no-r32
11986     0/imm32/no-imm32
11987     1/imm32/disp32-is-first-inout
11988     0/imm32/no-output
11989     0x11/imm32/alloc-id:fake
11990     _Primitive-break-if-<-named/imm32/next
11991 _Primitive-break-if-<-named:  # (payload primitive)
11992     0x11/imm32/alloc-id:fake:payload
11993     0x11/imm32/alloc-id:fake
11994     _string-break-if-</imm32/name
11995     0x11/imm32/alloc-id:fake
11996     Single-lit-var/imm32/inouts
11997     0/imm32/no-outputs
11998     0/imm32/no-outputs
11999     0x11/imm32/alloc-id:fake
12000     _string_0f_8c_jump_label/imm32/subx-name
12001     0/imm32/no-rm32
12002     0/imm32/no-r32
12003     0/imm32/no-imm32
12004     1/imm32/disp32-is-first-inout
12005     0/imm32/no-output
12006     0x11/imm32/alloc-id:fake
12007     _Primitive-break-if->=-named/imm32/next
12008 _Primitive-break-if->=-named:  # (payload primitive)
12009     0x11/imm32/alloc-id:fake:payload
12010     0x11/imm32/alloc-id:fake
12011     _string-break-if->=/imm32/name
12012     0x11/imm32/alloc-id:fake
12013     Single-lit-var/imm32/inouts
12014     0/imm32/no-outputs
12015     0/imm32/no-outputs
12016     0x11/imm32/alloc-id:fake
12017     _string_0f_8d_jump_label/imm32/subx-name
12018     0/imm32/no-rm32
12019     0/imm32/no-r32
12020     0/imm32/no-imm32
12021     1/imm32/disp32-is-first-inout
12022     0/imm32/no-output
12023     0x11/imm32/alloc-id:fake
12024     _Primitive-break-if-<=-named/imm32/next
12025 _Primitive-break-if-<=-named:  # (payload primitive)
12026     0x11/imm32/alloc-id:fake:payload
12027     0x11/imm32/alloc-id:fake
12028     _string-break-if-<=/imm32/name
12029     0x11/imm32/alloc-id:fake
12030     Single-lit-var/imm32/inouts
12031     0/imm32/no-outputs
12032     0/imm32/no-outputs
12033     0x11/imm32/alloc-id:fake
12034     _string_0f_8e_jump_label/imm32/subx-name
12035     0/imm32/no-rm32
12036     0/imm32/no-r32
12037     0/imm32/no-imm32
12038     1/imm32/disp32-is-first-inout
12039     0/imm32/no-output
12040     0x11/imm32/alloc-id:fake
12041     _Primitive-break-if->-named/imm32/next
12042 _Primitive-break-if->-named:  # (payload primitive)
12043     0x11/imm32/alloc-id:fake:payload
12044     0x11/imm32/alloc-id:fake
12045     _string-break-if->/imm32/name
12046     0x11/imm32/alloc-id:fake
12047     Single-lit-var/imm32/inouts
12048     0/imm32/no-outputs
12049     0/imm32/no-outputs
12050     0x11/imm32/alloc-id:fake
12051     _string_0f_8f_jump_label/imm32/subx-name
12052     0/imm32/no-rm32
12053     0/imm32/no-r32
12054     0/imm32/no-imm32
12055     1/imm32/disp32-is-first-inout
12056     0/imm32/no-output
12057     0x11/imm32/alloc-id:fake
12058     _Primitive-break-named/imm32/next
12059 _Primitive-break-named:  # (payload primitive)
12060     0x11/imm32/alloc-id:fake:payload
12061     0x11/imm32/alloc-id:fake
12062     _string-break/imm32/name
12063     0x11/imm32/alloc-id:fake
12064     Single-lit-var/imm32/inouts
12065     0/imm32/no-outputs
12066     0/imm32/no-outputs
12067     0x11/imm32/alloc-id:fake
12068     _string_e9_jump_label/imm32/subx-name
12069     0/imm32/no-rm32
12070     0/imm32/no-r32
12071     0/imm32/no-imm32
12072     1/imm32/disp32-is-first-inout
12073     0/imm32/no-output
12074     0x11/imm32/alloc-id:fake
12075     _Primitive-loop-if-addr<-named/imm32/next
12076 _Primitive-loop-if-addr<-named:  # (payload primitive)
12077     0x11/imm32/alloc-id:fake:payload
12078     0x11/imm32/alloc-id:fake
12079     _string-loop-if-addr</imm32/name
12080     0x11/imm32/alloc-id:fake
12081     Single-lit-var/imm32/inouts
12082     0/imm32/no-outputs
12083     0/imm32/no-outputs
12084     0x11/imm32/alloc-id:fake
12085     _string_0f_82_jump_label/imm32/subx-name
12086     0/imm32/no-rm32
12087     0/imm32/no-r32
12088     0/imm32/no-imm32
12089     1/imm32/disp32-is-first-inout
12090     0/imm32/no-output
12091     0x11/imm32/alloc-id:fake
12092     _Primitive-loop-if-addr>=-named/imm32/next
12093 _Primitive-loop-if-addr>=-named:  # (payload primitive)
12094     0x11/imm32/alloc-id:fake:payload
12095     0x11/imm32/alloc-id:fake
12096     _string-loop-if-addr>=/imm32/name
12097     0x11/imm32/alloc-id:fake
12098     Single-lit-var/imm32/inouts
12099     0/imm32/no-outputs
12100     0/imm32/no-outputs
12101     0x11/imm32/alloc-id:fake
12102     _string_0f_83_jump_label/imm32/subx-name
12103     0/imm32/no-rm32
12104     0/imm32/no-r32
12105     0/imm32/no-imm32
12106     1/imm32/disp32-is-first-inout
12107     0/imm32/no-output
12108     0x11/imm32/alloc-id:fake
12109     _Primitive-loop-if-=-named/imm32/next
12110 _Primitive-loop-if-=-named:  # (payload primitive)
12111     0x11/imm32/alloc-id:fake:payload
12112     0x11/imm32/alloc-id:fake
12113     _string-loop-if-=/imm32/name
12114     0x11/imm32/alloc-id:fake
12115     Single-lit-var/imm32/inouts
12116     0/imm32/no-outputs
12117     0/imm32/no-outputs
12118     0x11/imm32/alloc-id:fake
12119     _string_0f_84_jump_label/imm32/subx-name
12120     0/imm32/no-rm32
12121     0/imm32/no-r32
12122     0/imm32/no-imm32
12123     1/imm32/disp32-is-first-inout
12124     0/imm32/no-output
12125     0x11/imm32/alloc-id:fake
12126     _Primitive-loop-if-!=-named/imm32/next
12127 _Primitive-loop-if-!=-named:  # (payload primitive)
12128     0x11/imm32/alloc-id:fake:payload
12129     0x11/imm32/alloc-id:fake
12130     _string-loop-if-!=/imm32/name
12131     0x11/imm32/alloc-id:fake
12132     Single-lit-var/imm32/inouts
12133     0/imm32/no-outputs
12134     0/imm32/no-outputs
12135     0x11/imm32/alloc-id:fake
12136     _string_0f_85_jump_label/imm32/subx-name
12137     0/imm32/no-rm32
12138     0/imm32/no-r32
12139     0/imm32/no-imm32
12140     1/imm32/disp32-is-first-inout
12141     0/imm32/no-output
12142     0x11/imm32/alloc-id:fake
12143     _Primitive-loop-if-addr<=-named/imm32/next
12144 _Primitive-loop-if-addr<=-named:  # (payload primitive)
12145     0x11/imm32/alloc-id:fake:payload
12146     0x11/imm32/alloc-id:fake
12147     _string-loop-if-addr<=/imm32/name
12148     0x11/imm32/alloc-id:fake
12149     Single-lit-var/imm32/inouts
12150     0/imm32/no-outputs
12151     0/imm32/no-outputs
12152     0x11/imm32/alloc-id:fake
12153     _string_0f_86_jump_label/imm32/subx-name
12154     0/imm32/no-rm32
12155     0/imm32/no-r32
12156     0/imm32/no-imm32
12157     1/imm32/disp32-is-first-inout
12158     0/imm32/no-output
12159     0x11/imm32/alloc-id:fake
12160     _Primitive-loop-if-addr>-named/imm32/next
12161 _Primitive-loop-if-addr>-named:  # (payload primitive)
12162     0x11/imm32/alloc-id:fake:payload
12163     0x11/imm32/alloc-id:fake
12164     _string-loop-if-addr>/imm32/name
12165     0x11/imm32/alloc-id:fake
12166     Single-lit-var/imm32/inouts
12167     0/imm32/no-outputs
12168     0/imm32/no-outputs
12169     0x11/imm32/alloc-id:fake
12170     _string_0f_87_jump_label/imm32/subx-name
12171     0/imm32/no-rm32
12172     0/imm32/no-r32
12173     0/imm32/no-imm32
12174     1/imm32/disp32-is-first-inout
12175     0/imm32/no-output
12176     0x11/imm32/alloc-id:fake
12177     _Primitive-loop-if-<-named/imm32/next
12178 _Primitive-loop-if-<-named:  # (payload primitive)
12179     0x11/imm32/alloc-id:fake:payload
12180     0x11/imm32/alloc-id:fake
12181     _string-loop-if-</imm32/name
12182     0x11/imm32/alloc-id:fake
12183     Single-lit-var/imm32/inouts
12184     0/imm32/no-outputs
12185     0/imm32/no-outputs
12186     0x11/imm32/alloc-id:fake
12187     _string_0f_8c_jump_label/imm32/subx-name
12188     0/imm32/no-rm32
12189     0/imm32/no-r32
12190     0/imm32/no-imm32
12191     1/imm32/disp32-is-first-inout
12192     0/imm32/no-output
12193     0x11/imm32/alloc-id:fake
12194     _Primitive-loop-if->=-named/imm32/next
12195 _Primitive-loop-if->=-named:  # (payload primitive)
12196     0x11/imm32/alloc-id:fake:payload
12197     0x11/imm32/alloc-id:fake
12198     _string-loop-if->=/imm32/name
12199     0x11/imm32/alloc-id:fake
12200     Single-lit-var/imm32/inouts
12201     0/imm32/no-outputs
12202     0/imm32/no-outputs
12203     0x11/imm32/alloc-id:fake
12204     _string_0f_8d_jump_label/imm32/subx-name
12205     0/imm32/no-rm32
12206     0/imm32/no-r32
12207     0/imm32/no-imm32
12208     1/imm32/disp32-is-first-inout
12209     0/imm32/no-output
12210     0x11/imm32/alloc-id:fake
12211     _Primitive-loop-if-<=-named/imm32/next
12212 _Primitive-loop-if-<=-named:  # (payload primitive)
12213     0x11/imm32/alloc-id:fake:payload
12214     0x11/imm32/alloc-id:fake
12215     _string-loop-if-<=/imm32/name
12216     0x11/imm32/alloc-id:fake
12217     Single-lit-var/imm32/inouts
12218     0/imm32/no-outputs
12219     0/imm32/no-outputs
12220     0x11/imm32/alloc-id:fake
12221     _string_0f_8e_jump_label/imm32/subx-name
12222     0/imm32/no-rm32
12223     0/imm32/no-r32
12224     0/imm32/no-imm32
12225     1/imm32/disp32-is-first-inout
12226     0/imm32/no-output
12227     0x11/imm32/alloc-id:fake
12228     _Primitive-loop-if->-named/imm32/next
12229 _Primitive-loop-if->-named:  # (payload primitive)
12230     0x11/imm32/alloc-id:fake:payload
12231     0x11/imm32/alloc-id:fake
12232     _string-loop-if->/imm32/name
12233     0x11/imm32/alloc-id:fake
12234     Single-lit-var/imm32/inouts
12235     0/imm32/no-outputs
12236     0/imm32/no-outputs
12237     0x11/imm32/alloc-id:fake
12238     _string_0f_8f_jump_label/imm32/subx-name
12239     0/imm32/no-rm32
12240     0/imm32/no-r32
12241     0/imm32/no-imm32
12242     1/imm32/disp32-is-first-inout
12243     0/imm32/no-output
12244     0x11/imm32/alloc-id:fake
12245     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
12246 _Primitive-loop-named:  # (payload primitive)
12247     0x11/imm32/alloc-id:fake:payload
12248     0x11/imm32/alloc-id:fake
12249     _string-loop/imm32/name
12250     0x11/imm32/alloc-id:fake
12251     Single-lit-var/imm32/inouts
12252     0/imm32/no-outputs
12253     0/imm32/no-outputs
12254     0x11/imm32/alloc-id:fake
12255     _string_e9_jump_label/imm32/subx-name
12256     0/imm32/no-rm32
12257     0/imm32/no-r32
12258     0/imm32/no-imm32
12259     1/imm32/disp32-is-first-inout
12260     0/imm32/no-output
12261     0/imm32/next
12262     0/imm32/next
12263 
12264 # string literals for Mu instructions
12265 _string-add:  # (payload array byte)
12266     0x11/imm32/alloc-id:fake:payload
12267     # "add"
12268     0x3/imm32/size
12269     0x61/a 0x64/d 0x64/d
12270 _string-address:  # (payload array byte)
12271     0x11/imm32/alloc-id:fake:payload
12272     # "address"
12273     0x7/imm32/size
12274     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
12275 _string-add-to:  # (payload array byte)
12276     0x11/imm32/alloc-id:fake:payload
12277     # "add-to"
12278     0x6/imm32/size
12279     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
12280 _string-and:  # (payload array byte)
12281     0x11/imm32/alloc-id:fake:payload
12282     # "and"
12283     0x3/imm32/size
12284     0x61/a 0x6e/n 0x64/d
12285 _string-and-with:  # (payload array byte)
12286     0x11/imm32/alloc-id:fake:payload
12287     # "and-with"
12288     0x8/imm32/size
12289     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12290 _string-break:  # (payload array byte)
12291     0x11/imm32/alloc-id:fake:payload
12292     # "break"
12293     0x5/imm32/size
12294     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
12295 _string-break-if-<:  # (payload array byte)
12296     0x11/imm32/alloc-id:fake:payload
12297     # "break-if-<"
12298     0xa/imm32/size
12299     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
12300 _string-break-if-<=:  # (payload array byte)
12301     0x11/imm32/alloc-id:fake:payload
12302     # "break-if-<="
12303     0xb/imm32/size
12304     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
12305 _string-break-if-=:  # (payload array byte)
12306     0x11/imm32/alloc-id:fake:payload
12307     # "break-if-="
12308     0xa/imm32/size
12309     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
12310 _string-break-if->:  # (payload array byte)
12311     0x11/imm32/alloc-id:fake:payload
12312     # "break-if->"
12313     0xa/imm32/size
12314     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
12315 _string-break-if->=:  # (payload array byte)
12316     0x11/imm32/alloc-id:fake:payload
12317     # "break-if->="
12318     0xb/imm32/size
12319     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
12320 _string-break-if-!=:  # (payload array byte)
12321     0x11/imm32/alloc-id:fake:payload
12322     # "break-if-!="
12323     0xb/imm32/size
12324     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
12325 _string-break-if-addr<:  # (payload array byte)
12326     0x11/imm32/alloc-id:fake:payload
12327     # "break-if-addr<"
12328     0xe/imm32/size
12329     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/<
12330 _string-break-if-addr<=:  # (payload array byte)
12331     0x11/imm32/alloc-id:fake:payload
12332     # "break-if-addr<="
12333     0xf/imm32/size
12334     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/=
12335 _string-break-if-addr>:  # (payload array byte)
12336     0x11/imm32/alloc-id:fake:payload
12337     # "break-if-addr>"
12338     0xe/imm32/size
12339     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/>
12340 _string-break-if-addr>=:  # (payload array byte)
12341     0x11/imm32/alloc-id:fake:payload
12342     # "break-if-addr>="
12343     0xf/imm32/size
12344     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/=
12345 _string-compare:  # (payload array byte)
12346     0x11/imm32/alloc-id:fake:payload
12347     # "compare"
12348     0x7/imm32/size
12349     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
12350 _string-copy:  # (payload array byte)
12351     0x11/imm32/alloc-id:fake:payload
12352     # "copy"
12353     0x4/imm32/size
12354     0x63/c 0x6f/o 0x70/p 0x79/y
12355 _string-copy-to:  # (payload array byte)
12356     0x11/imm32/alloc-id:fake:payload
12357     # "copy-to"
12358     0x7/imm32/size
12359     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
12360 _string-decrement:  # (payload array byte)
12361     0x11/imm32/alloc-id:fake:payload
12362     # "decrement"
12363     0x9/imm32/size
12364     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12365 _string-increment:  # (payload array byte)
12366     0x11/imm32/alloc-id:fake:payload
12367     # "increment"
12368     0x9/imm32/size
12369     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12370 _string-loop:  # (payload array byte)
12371     0x11/imm32/alloc-id:fake:payload
12372     # "loop"
12373     0x4/imm32/size
12374     0x6c/l 0x6f/o 0x6f/o 0x70/p
12375 _string-loop-if-<:  # (payload array byte)
12376     0x11/imm32/alloc-id:fake:payload
12377     # "loop-if-<"
12378     0x9/imm32/size
12379     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
12380 _string-loop-if-<=:  # (payload array byte)
12381     0x11/imm32/alloc-id:fake:payload
12382     # "loop-if-<="
12383     0xa/imm32/size
12384     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
12385 _string-loop-if-=:  # (payload array byte)
12386     0x11/imm32/alloc-id:fake:payload
12387     # "loop-if-="
12388     0x9/imm32/size
12389     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
12390 _string-loop-if->:  # (payload array byte)
12391     0x11/imm32/alloc-id:fake:payload
12392     # "loop-if->"
12393     0x9/imm32/size
12394     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
12395 _string-loop-if->=:  # (payload array byte)
12396     0x11/imm32/alloc-id:fake:payload
12397     # "loop-if->="
12398     0xa/imm32/size
12399     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
12400 _string-loop-if-!=:  # (payload array byte)
12401     0x11/imm32/alloc-id:fake:payload
12402     # "loop-if-!="
12403     0xa/imm32/size
12404     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
12405 _string-loop-if-addr<:  # (payload array byte)
12406     0x11/imm32/alloc-id:fake:payload
12407     # "loop-if-addr<"
12408     0xd/imm32/size
12409     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/<
12410 _string-loop-if-addr<=:  # (payload array byte)
12411     0x11/imm32/alloc-id:fake:payload
12412     # "loop-if-addr<="
12413     0xe/imm32/size
12414     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/=
12415 _string-loop-if-addr>:  # (payload array byte)
12416     0x11/imm32/alloc-id:fake:payload
12417     # "loop-if-addr>"
12418     0xd/imm32/size
12419     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/>
12420 _string-loop-if-addr>=:  # (payload array byte)
12421     0x11/imm32/alloc-id:fake:payload
12422     # "loop-if-addr>="
12423     0xe/imm32/size
12424     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/=
12425 _string-multiply:  # (payload array byte)
12426     0x11/imm32/alloc-id:fake:payload
12427     # "multiply"
12428     0x8/imm32/size
12429     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
12430 _string-or:  # (payload array byte)
12431     0x11/imm32/alloc-id:fake:payload
12432     # "or"
12433     0x2/imm32/size
12434     0x6f/o 0x72/r
12435 _string-or-with:  # (payload array byte)
12436     0x11/imm32/alloc-id:fake:payload
12437     # "or-with"
12438     0x7/imm32/size
12439     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12440 _string-subtract:  # (payload array byte)
12441     0x11/imm32/alloc-id:fake:payload
12442     # "subtract"
12443     0x8/imm32/size
12444     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12445 _string-subtract-from:  # (payload array byte)
12446     0x11/imm32/alloc-id:fake:payload
12447     # "subtract-from"
12448     0xd/imm32/size
12449     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
12450 _string-xor:  # (payload array byte)
12451     0x11/imm32/alloc-id:fake:payload
12452     # "xor"
12453     0x3/imm32/size
12454     0x78/x 0x6f/o 0x72/r
12455 _string-xor-with:  # (payload array byte)
12456     0x11/imm32/alloc-id:fake:payload
12457     # "xor-with"
12458     0x8/imm32/size
12459     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12460 
12461 # string literals for SubX instructions
12462 _string_01_add_to:  # (payload array byte)
12463     0x11/imm32/alloc-id:fake:payload
12464     # "01/add-to"
12465     0x9/imm32/size
12466     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
12467 _string_03_add:  # (payload array byte)
12468     0x11/imm32/alloc-id:fake:payload
12469     # "03/add"
12470     0x6/imm32/size
12471     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
12472 _string_05_add_to_eax:  # (payload array byte)
12473     0x11/imm32/alloc-id:fake:payload
12474     # "05/add-to-eax"
12475     0xd/imm32/size
12476     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
12477 _string_09_or_with:  # (payload array byte)
12478     0x11/imm32/alloc-id:fake:payload
12479     # "09/or-with"
12480     0xa/imm32/size
12481     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12482 _string_0b_or:  # (payload array byte)
12483     0x11/imm32/alloc-id:fake:payload
12484     # "0b/or"
12485     0x5/imm32/size
12486     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
12487 _string_0d_or_with_eax:  # (payload array byte)
12488     0x11/imm32/alloc-id:fake:payload
12489     # "0d/or-with-eax"
12490     0xe/imm32/size
12491     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
12492 _string_0f_82_jump_label:  # (payload array byte)
12493     0x11/imm32/alloc-id:fake:payload
12494     # "0f 82/jump-if-addr<"
12495     0x13/imm32/size
12496     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/<
12497 _string_0f_82_jump_break:  # (payload array byte)
12498     0x11/imm32/alloc-id:fake:payload
12499     # "0f 82/jump-if-addr< break/disp32"
12500     0x20/imm32/size
12501     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
12502 _string_0f_82_jump_loop:  # (payload array byte)
12503     0x11/imm32/alloc-id:fake:payload
12504     # "0f 82/jump-if-addr< loop/disp32"
12505     0x1f/imm32/size
12506     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
12507 _string_0f_83_jump_label:  # (payload array byte)
12508     0x11/imm32/alloc-id:fake:payload
12509     # "0f 83/jump-if-addr>="
12510     0x14/imm32/size
12511     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/=
12512 _string_0f_83_jump_break:  # (payload array byte)
12513     0x11/imm32/alloc-id:fake:payload
12514     # "0f 83/jump-if-addr>= break/disp32"
12515     0x21/imm32/size
12516     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
12517 _string_0f_83_jump_loop:  # (payload array byte)
12518     0x11/imm32/alloc-id:fake:payload
12519     # "0f 83/jump-if-addr>= loop/disp32"
12520     0x20/imm32/size
12521     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
12522 _string_0f_84_jump_label:  # (payload array byte)
12523     0x11/imm32/alloc-id:fake:payload
12524     # "0f 84/jump-if-="
12525     0xf/imm32/size
12526     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/=
12527 _string_0f_84_jump_break:  # (payload array byte)
12528     0x11/imm32/alloc-id:fake:payload
12529     # "0f 84/jump-if-= break/disp32"
12530     0x1c/imm32/size
12531     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
12532 _string_0f_84_jump_loop:  # (payload array byte)
12533     0x11/imm32/alloc-id:fake:payload
12534     # "0f 84/jump-if-= loop/disp32"
12535     0x1b/imm32/size
12536     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
12537 _string_0f_85_jump_label:  # (payload array byte)
12538     0x11/imm32/alloc-id:fake:payload
12539     # "0f 85/jump-if-!="
12540     0x10/imm32/size
12541     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/=
12542 _string_0f_85_jump_break:  # (payload array byte)
12543     0x11/imm32/alloc-id:fake:payload
12544     # "0f 85/jump-if-!= break/disp32"
12545     0x1d/imm32/size
12546     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
12547 _string_0f_85_jump_loop:  # (payload array byte)
12548     0x11/imm32/alloc-id:fake:payload
12549     # "0f 85/jump-if-!= loop/disp32"
12550     0x1c/imm32/size
12551     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
12552 _string_0f_86_jump_label:  # (payload array byte)
12553     0x11/imm32/alloc-id:fake:payload
12554     # "0f 86/jump-if-addr<="
12555     0x14/imm32/size
12556     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/=
12557 _string_0f_86_jump_break:  # (payload array byte)
12558     0x11/imm32/alloc-id:fake:payload
12559     # "0f 86/jump-if-addr<= break/disp32"
12560     0x21/imm32/size
12561     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
12562 _string_0f_86_jump_loop:  # (payload array byte)
12563     0x11/imm32/alloc-id:fake:payload
12564     # "0f 86/jump-if-addr<= loop/disp32"
12565     0x20/imm32/size
12566     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
12567 _string_0f_87_jump_label:  # (payload array byte)
12568     0x11/imm32/alloc-id:fake:payload
12569     # "0f 87/jump-if-addr>"
12570     0x13/imm32/size
12571     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/>
12572 _string_0f_87_jump_break:  # (payload array byte)
12573     0x11/imm32/alloc-id:fake:payload
12574     # "0f 87/jump-if-addr> break/disp32"
12575     0x20/imm32/size
12576     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
12577 _string_0f_87_jump_loop:  # (payload array byte)
12578     0x11/imm32/alloc-id:fake:payload
12579     # "0f 87/jump-if-addr> loop/disp32"
12580     0x1f/imm32/size
12581     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
12582 _string_0f_8c_jump_label:  # (payload array byte)
12583     0x11/imm32/alloc-id:fake:payload
12584     # "0f 8c/jump-if-<"
12585     0xf/imm32/size
12586     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/<
12587 _string_0f_8c_jump_break:  # (payload array byte)
12588     0x11/imm32/alloc-id:fake:payload
12589     # "0f 8c/jump-if-< break/disp32"
12590     0x1c/imm32/size
12591     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
12592 _string_0f_8c_jump_loop:  # (payload array byte)
12593     0x11/imm32/alloc-id:fake:payload
12594     # "0f 8c/jump-if-< loop/disp32"
12595     0x1b/imm32/size
12596     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
12597 _string_0f_8d_jump_label:  # (payload array byte)
12598     0x11/imm32/alloc-id:fake:payload
12599     # "0f 8d/jump-if->="
12600     0x10/imm32/size
12601     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/=
12602 _string_0f_8d_jump_break:  # (payload array byte)
12603     0x11/imm32/alloc-id:fake:payload
12604     # "0f 8d/jump-if->= break/disp32"
12605     0x1d/imm32/size
12606     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
12607 _string_0f_8d_jump_loop:  # (payload array byte)
12608     0x11/imm32/alloc-id:fake:payload
12609     # "0f 8d/jump-if->= loop/disp32"
12610     0x1c/imm32/size
12611     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
12612 _string_0f_8e_jump_label:  # (payload array byte)
12613     0x11/imm32/alloc-id:fake:payload
12614     # "0f 8e/jump-if-<="
12615     0x10/imm32/size
12616     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/=
12617 _string_0f_8e_jump_break:  # (payload array byte)
12618     0x11/imm32/alloc-id:fake:payload
12619     # "0f 8e/jump-if-<= break/disp32"
12620     0x1d/imm32/size
12621     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
12622 _string_0f_8e_jump_loop:  # (payload array byte)
12623     0x11/imm32/alloc-id:fake:payload
12624     # "0f 8e/jump-if-<= loop/disp32"
12625     0x1c/imm32/size
12626     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
12627 _string_0f_8f_jump_label:  # (payload array byte)
12628     0x11/imm32/alloc-id:fake:payload
12629     # "0f 8f/jump-if->"
12630     0xf/imm32/size
12631     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/>
12632 _string_0f_8f_jump_break:  # (payload array byte)
12633     0x11/imm32/alloc-id:fake:payload
12634     # "0f 8f/jump-if-> break/disp32"
12635     0x1c/imm32/size
12636     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
12637 _string_0f_8f_jump_loop:  # (payload array byte)
12638     0x11/imm32/alloc-id:fake:payload
12639     # "0f 8f/jump-if-> loop/disp32"
12640     0x1b/imm32/size
12641     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
12642 _string_0f_af_multiply:  # (payload array byte)
12643     0x11/imm32/alloc-id:fake:payload
12644     # "0f af/multiply"
12645     0xe/imm32/size
12646     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
12647 _string_21_and_with:  # (payload array byte)
12648     0x11/imm32/alloc-id:fake:payload
12649     # "21/and-with"
12650     0xb/imm32/size
12651     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12652 _string_23_and:  # (payload array byte)
12653     0x11/imm32/alloc-id:fake:payload
12654     # "23/and"
12655     0x6/imm32/size
12656     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
12657 _string_25_and_with_eax:  # (payload array byte)
12658     0x11/imm32/alloc-id:fake:payload
12659     # "25/and-with-eax"
12660     0xf/imm32/size
12661     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
12662 _string_29_subtract_from:  # (payload array byte)
12663     0x11/imm32/alloc-id:fake:payload
12664     # "29/subtract-from"
12665     0x10/imm32/size
12666     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
12667 _string_2b_subtract:  # (payload array byte)
12668     0x11/imm32/alloc-id:fake:payload
12669     # "2b/subtract"
12670     0xb/imm32/size
12671     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12672 _string_2d_subtract_from_eax:  # (payload array byte)
12673     0x11/imm32/alloc-id:fake:payload
12674     # "2d/subtract-from-eax"
12675     0x14/imm32/size
12676     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
12677 _string_31_xor_with:  # (payload array byte)
12678     0x11/imm32/alloc-id:fake:payload
12679     # "31/xor-with"
12680     0xb/imm32/size
12681     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12682 _string_33_xor:  # (payload array byte)
12683     0x11/imm32/alloc-id:fake:payload
12684     # "33/xor"
12685     0x6/imm32/size
12686     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
12687 _string_35_xor_with_eax:  # (payload array byte)
12688     0x11/imm32/alloc-id:fake:payload
12689     # "35/xor-with-eax"
12690     0xf/imm32/size
12691     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
12692 _string_39_compare->:  # (payload array byte)
12693     0x11/imm32/alloc-id:fake:payload
12694     # "39/compare->"
12695     0xc/imm32/size
12696     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
12697 _string_3b_compare<-:  # (payload array byte)
12698     0x11/imm32/alloc-id:fake:payload
12699     # "3b/compare<-"
12700     0xc/imm32/size
12701     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
12702 _string_3d_compare_eax_with:  # (payload array byte)
12703     0x11/imm32/alloc-id:fake:payload
12704     # "3d/compare-eax-with"
12705     0x13/imm32/size
12706     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
12707 _string_40_increment_eax:  # (payload array byte)
12708     0x11/imm32/alloc-id:fake:payload
12709     # "40/increment-eax"
12710     0x10/imm32/size
12711     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
12712 _string_41_increment_ecx:  # (payload array byte)
12713     0x11/imm32/alloc-id:fake:payload
12714     # "41/increment-ecx"
12715     0x10/imm32/size
12716     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
12717 _string_42_increment_edx:  # (payload array byte)
12718     0x11/imm32/alloc-id:fake:payload
12719     # "42/increment-edx"
12720     0x10/imm32/size
12721     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
12722 _string_43_increment_ebx:  # (payload array byte)
12723     0x11/imm32/alloc-id:fake:payload
12724     # "43/increment-ebx"
12725     0x10/imm32/size
12726     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
12727 _string_46_increment_esi:  # (payload array byte)
12728     0x11/imm32/alloc-id:fake:payload
12729     # "46/increment-esi"
12730     0x10/imm32/size
12731     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
12732 _string_47_increment_edi:  # (payload array byte)
12733     0x11/imm32/alloc-id:fake:payload
12734     # "47/increment-edi"
12735     0x10/imm32/size
12736     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
12737 _string_48_decrement_eax:  # (payload array byte)
12738     0x11/imm32/alloc-id:fake:payload
12739     # "48/decrement-eax"
12740     0x10/imm32/size
12741     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
12742 _string_49_decrement_ecx:  # (payload array byte)
12743     0x11/imm32/alloc-id:fake:payload
12744     # "49/decrement-ecx"
12745     0x10/imm32/size
12746     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
12747 _string_4a_decrement_edx:  # (payload array byte)
12748     0x11/imm32/alloc-id:fake:payload
12749     # "4a/decrement-edx"
12750     0x10/imm32/size
12751     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
12752 _string_4b_decrement_ebx:  # (payload array byte)
12753     0x11/imm32/alloc-id:fake:payload
12754     # "4b/decrement-ebx"
12755     0x10/imm32/size
12756     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
12757 _string_4e_decrement_esi:  # (payload array byte)
12758     0x11/imm32/alloc-id:fake:payload
12759     # "4e/decrement-esi"
12760     0x10/imm32/size
12761     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
12762 _string_4f_decrement_edi:  # (payload array byte)
12763     0x11/imm32/alloc-id:fake:payload
12764     # "4f/decrement-edi"
12765     0x10/imm32/size
12766     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
12767 _string_81_subop_add:  # (payload array byte)
12768     0x11/imm32/alloc-id:fake:payload
12769     # "81 0/subop/add"
12770     0xe/imm32/size
12771     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
12772 _string_81_subop_or:  # (payload array byte)
12773     0x11/imm32/alloc-id:fake:payload
12774     # "81 1/subop/or"
12775     0xd/imm32/size
12776     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
12777 _string_81_subop_and:  # (payload array byte)
12778     0x11/imm32/alloc-id:fake:payload
12779     # "81 4/subop/and"
12780     0xe/imm32/size
12781     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
12782 _string_81_subop_subtract:  # (payload array byte)
12783     0x11/imm32/alloc-id:fake:payload
12784     # "81 5/subop/subtract"
12785     0x13/imm32/size
12786     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
12787 _string_81_subop_xor:  # (payload array byte)
12788     0x11/imm32/alloc-id:fake:payload
12789     # "81 6/subop/xor"
12790     0xe/imm32/size
12791     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
12792 _string_81_subop_compare:  # (payload array byte)
12793     0x11/imm32/alloc-id:fake:payload
12794     # "81 7/subop/compare"
12795     0x12/imm32/size
12796     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
12797 _string_89_<-:  # (payload array byte)
12798     0x11/imm32/alloc-id:fake:payload
12799     # "89/<-"
12800     0x5/imm32/size
12801     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
12802 _string_8b_->:  # (payload array byte)
12803     0x11/imm32/alloc-id:fake:payload
12804     # "8b/->"
12805     0x5/imm32/size
12806     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
12807 _string_8d_copy_address:  # (payload array byte)
12808     0x11/imm32/alloc-id:fake:payload
12809     # "8d/copy-address"
12810     0xf/imm32/size
12811     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
12812 _string_b8_copy_to_eax:  # (payload array byte)
12813     0x11/imm32/alloc-id:fake:payload
12814     # "b8/copy-to-eax"
12815     0xe/imm32/size
12816     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
12817 _string_b9_copy_to_ecx:  # (payload array byte)
12818     0x11/imm32/alloc-id:fake:payload
12819     # "b9/copy-to-ecx"
12820     0xe/imm32/size
12821     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
12822 _string_ba_copy_to_edx:  # (payload array byte)
12823     0x11/imm32/alloc-id:fake:payload
12824     # "ba/copy-to-edx"
12825     0xe/imm32/size
12826     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
12827 _string_bb_copy_to_ebx:  # (payload array byte)
12828     0x11/imm32/alloc-id:fake:payload
12829     # "bb/copy-to-ebx"
12830     0xe/imm32/size
12831     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
12832 _string_be_copy_to_esi:  # (payload array byte)
12833     0x11/imm32/alloc-id:fake:payload
12834     # "be/copy-to-esi"
12835     0xe/imm32/size
12836     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
12837 _string_bf_copy_to_edi:  # (payload array byte)
12838     0x11/imm32/alloc-id:fake:payload
12839     # "bf/copy-to-edi"
12840     0xe/imm32/size
12841     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
12842 _string_c7_subop_copy:  # (payload array byte)
12843     0x11/imm32/alloc-id:fake:payload
12844     # "c7 0/subop/copy"
12845     0xf/imm32/size
12846     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
12847 _string_e9_jump_label:  # (payload array byte)
12848     0x11/imm32/alloc-id:fake:payload
12849     # "e9/jump"
12850     0x7/imm32/size
12851     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
12852 _string_e9_jump_break:  # (payload array byte)
12853     0x11/imm32/alloc-id:fake:payload
12854     # "e9/jump break/disp32"
12855     0x14/imm32/size
12856     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
12857 _string_e9_jump_loop:  # (payload array byte)
12858     0x11/imm32/alloc-id:fake:payload
12859     # "e9/jump loop/disp32"
12860     0x13/imm32/size
12861     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
12862 _string_ff_subop_increment:  # (payload array byte)
12863     0x11/imm32/alloc-id:fake:payload
12864     # "ff 0/subop/increment"
12865     0x14/imm32/size
12866     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
12867 _string_ff_subop_decrement:  # (payload array byte)
12868     0x11/imm32/alloc-id:fake:payload
12869     # "ff 1/subop/decrement"
12870     0x14/imm32/size
12871     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
12872 
12873 Single-int-var-in-mem:  # (payload list var)
12874     0x11/imm32/alloc-id:fake:payload
12875     0x11/imm32/alloc-id:fake
12876     Int-var-in-mem/imm32
12877     0/imm32/next
12878     0/imm32/next
12879 
12880 Int-var-in-mem:  # (payload var)
12881     0x11/imm32/alloc-id:fake:payload
12882     0/imm32/name
12883     0/imm32/name
12884     0x11/imm32/alloc-id:fake
12885     Type-int/imm32
12886     1/imm32/some-block-depth
12887     1/imm32/some-stack-offset
12888     0/imm32/no-register
12889     0/imm32/no-register
12890 
12891 Two-args-int-stack-int-reg:  # (payload list var)
12892     0x11/imm32/alloc-id:fake:payload
12893     0x11/imm32/alloc-id:fake
12894     Int-var-in-mem/imm32
12895     0x11/imm32/alloc-id:fake
12896     Single-int-var-in-some-register/imm32/next
12897 
12898 Two-args-int-reg-int-stack:  # (payload list var)
12899     0x11/imm32/alloc-id:fake:payload
12900     0x11/imm32/alloc-id:fake
12901     Int-var-in-some-register/imm32
12902     0x11/imm32/alloc-id:fake
12903     Single-int-var-in-mem/imm32/next
12904 
12905 Two-args-int-eax-int-literal:  # (payload list var)
12906     0x11/imm32/alloc-id:fake:payload
12907     0x11/imm32/alloc-id:fake
12908     Int-var-in-eax/imm32
12909     0x11/imm32/alloc-id:fake
12910     Single-lit-var/imm32/next
12911 
12912 Int-var-and-literal:  # (payload list var)
12913     0x11/imm32/alloc-id:fake:payload
12914     0x11/imm32/alloc-id:fake
12915     Int-var-in-mem/imm32
12916     0x11/imm32/alloc-id:fake
12917     Single-lit-var/imm32/next
12918 
12919 Int-var-in-register-and-literal:  # (payload list var)
12920     0x11/imm32/alloc-id:fake:payload
12921     0x11/imm32/alloc-id:fake
12922     Int-var-in-some-register/imm32
12923     0x11/imm32/alloc-id:fake
12924     Single-lit-var/imm32/next
12925 
12926 Single-int-var-in-some-register:  # (payload list var)
12927     0x11/imm32/alloc-id:fake:payload
12928     0x11/imm32/alloc-id:fake
12929     Int-var-in-some-register/imm32
12930     0/imm32/next
12931     0/imm32/next
12932 
12933 Single-addr-var-in-some-register:  # (payload list var)
12934     0x11/imm32/alloc-id:fake:payload
12935     0x11/imm32/alloc-id:fake
12936     Addr-var-in-some-register/imm32
12937     0/imm32/next
12938     0/imm32/next
12939 
12940 Int-var-in-some-register:  # (payload var)
12941     0x11/imm32/alloc-id:fake:payload
12942     0/imm32/name
12943     0/imm32/name
12944     0x11/imm32/alloc-id:fake
12945     Type-int/imm32
12946     1/imm32/some-block-depth
12947     0/imm32/no-stack-offset
12948     0x11/imm32/alloc-id:fake
12949     Any-register/imm32
12950 
12951 Any-register:  # (payload array byte)
12952   0x11/imm32/alloc-id:fake:payload
12953   1/imm32/size
12954   # data
12955   2a/asterisk
12956 
12957 Addr-var-in-some-register:  # (payload var)
12958     0x11/imm32/alloc-id:fake:payload
12959     0/imm32/name
12960     0/imm32/name
12961     0x11/imm32/alloc-id:fake
12962     Type-addr/imm32
12963     1/imm32/some-block-depth
12964     0/imm32/no-stack-offset
12965     0x11/imm32/alloc-id:fake
12966     Any-register/imm32
12967 
12968 Single-int-var-in-eax:  # (payload list var)
12969     0x11/imm32/alloc-id:fake:payload
12970     0x11/imm32/alloc-id:fake
12971     Int-var-in-eax/imm32
12972     0/imm32/next
12973     0/imm32/next
12974 
12975 Int-var-in-eax:
12976     0x11/imm32/alloc-id:fake:payload
12977     0/imm32/name
12978     0/imm32/name
12979     0x11/imm32/alloc-id:fake
12980     Type-int/imm32
12981     1/imm32/some-block-depth
12982     0/imm32/no-stack-offset
12983     0x11/imm32/alloc-id:fake
12984     $Register-eax/imm32
12985 
12986 Single-int-var-in-ecx:  # (payload list var)
12987     0x11/imm32/alloc-id:fake:payload
12988     0x11/imm32/alloc-id:fake
12989     Int-var-in-ecx/imm32
12990     0/imm32/next
12991     0/imm32/next
12992 
12993 Int-var-in-ecx:
12994     0x11/imm32/alloc-id:fake:payload
12995     0/imm32/name
12996     0/imm32/name
12997     0x11/imm32/alloc-id:fake
12998     Type-int/imm32
12999     1/imm32/some-block-depth
13000     0/imm32/no-stack-offset
13001     0x11/imm32/alloc-id:fake
13002     $Register-ecx/imm32/register
13003 
13004 Single-int-var-in-edx:  # (payload list var)
13005     0x11/imm32/alloc-id:fake:payload
13006     0x11/imm32/alloc-id:fake
13007     Int-var-in-edx/imm32
13008     0/imm32/next
13009     0/imm32/next
13010 
13011 Int-var-in-edx:  # (payload list var)
13012     0x11/imm32/alloc-id:fake:payload
13013     0/imm32/name
13014     0/imm32/name
13015     0x11/imm32/alloc-id:fake
13016     Type-int/imm32
13017     1/imm32/some-block-depth
13018     0/imm32/no-stack-offset
13019     0x11/imm32/alloc-id:fake
13020     $Register-edx/imm32/register
13021 
13022 Single-int-var-in-ebx:  # (payload list var)
13023     0x11/imm32/alloc-id:fake:payload
13024     0x11/imm32/alloc-id:fake
13025     Int-var-in-ebx/imm32
13026     0/imm32/next
13027     0/imm32/next
13028 
13029 Int-var-in-ebx:  # (payload list var)
13030     0x11/imm32/alloc-id:fake:payload
13031     0/imm32/name
13032     0/imm32/name
13033     0x11/imm32/alloc-id:fake
13034     Type-int/imm32
13035     1/imm32/some-block-depth
13036     0/imm32/no-stack-offset
13037     0x11/imm32/alloc-id:fake
13038     $Register-ebx/imm32/register
13039 
13040 Single-int-var-in-esi:  # (payload list var)
13041     0x11/imm32/alloc-id:fake:payload
13042     0x11/imm32/alloc-id:fake
13043     Int-var-in-esi/imm32
13044     0/imm32/next
13045     0/imm32/next
13046 
13047 Int-var-in-esi:  # (payload list var)
13048     0x11/imm32/alloc-id:fake:payload
13049     0/imm32/name
13050     0/imm32/name
13051     0x11/imm32/alloc-id:fake
13052     Type-int/imm32
13053     1/imm32/some-block-depth
13054     0/imm32/no-stack-offset
13055     0x11/imm32/alloc-id:fake
13056     $Register-esi/imm32/register
13057 
13058 Single-int-var-in-edi:  # (payload list var)
13059     0x11/imm32/alloc-id:fake:payload
13060     0x11/imm32/alloc-id:fake
13061     Int-var-in-edi/imm32
13062     0/imm32/next
13063     0/imm32/next
13064 
13065 Int-var-in-edi:  # (payload list var)
13066     0x11/imm32/alloc-id:fake:payload
13067     0/imm32/name
13068     0/imm32/name
13069     0x11/imm32/alloc-id:fake
13070     Type-int/imm32
13071     1/imm32/some-block-depth
13072     0/imm32/no-stack-offset
13073     0x11/imm32/alloc-id:fake
13074     $Register-edi/imm32/register
13075 
13076 Single-lit-var:  # (payload list var)
13077     0x11/imm32/alloc-id:fake:payload
13078     0x11/imm32/alloc-id:fake
13079     Lit-var/imm32
13080     0/imm32/next
13081     0/imm32/next
13082 
13083 Lit-var:  # (payload var)
13084     0x11/imm32/alloc-id:fake:payload
13085     0/imm32/name
13086     0/imm32/name
13087     0x11/imm32/alloc-id:fake
13088     Type-literal/imm32
13089     1/imm32/some-block-depth
13090     0/imm32/no-stack-offset
13091     0/imm32/no-register
13092     0/imm32/no-register
13093 
13094 Type-int:  # (payload tree type-id)
13095     0x11/imm32/alloc-id:fake:payload
13096     1/imm32/left-is-atom
13097     1/imm32/value:int
13098     0/imm32/left:unused
13099     0/imm32/right:null
13100     0/imm32/right:null
13101 
13102 Type-literal:  # (payload tree type-id)
13103     0x11/imm32/alloc-id:fake:payload
13104     1/imm32/is-atom
13105     0/imm32/value:literal
13106     0/imm32/left:unused
13107     0/imm32/right:null
13108     0/imm32/right:null
13109 
13110 Type-addr:  # (payload tree type-id)
13111     0x11/imm32/alloc-id:fake:payload
13112     1/imm32/is-atom
13113     2/imm32/value:addr
13114     0/imm32/left:unused
13115     0/imm32/right:null
13116     0/imm32/right:null
13117 
13118 == code
13119 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive)
13120     # . prologue
13121     55/push-ebp
13122     89/<- %ebp 4/r32/esp
13123     # . save registers
13124     50/push-eax
13125     51/push-ecx
13126     # ecx = primitive
13127     8b/-> *(ebp+0x10) 1/r32/ecx
13128     # emit primitive name
13129     (emit-indent *(ebp+8) *Curr-block-depth)
13130     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
13131     (write-buffered *(ebp+8) %eax)
13132     # emit rm32 if necessary
13133     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc))  # out, Primitive-subx-rm32, stmt
13134     # emit r32 if necessary
13135     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # out, Primitive-subx-r32, stmt
13136     # emit imm32 if necessary
13137     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # out, Primitive-subx-imm32, stmt
13138     # emit disp32 if necessary
13139     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # out, Primitive-subx-disp32, stmt
13140     (write-buffered *(ebp+8) Newline)
13141 $emit-subx-primitive:end:
13142     # . restore registers
13143     59/pop-to-ecx
13144     58/pop-to-eax
13145     # . epilogue
13146     89/<- %esp 5/r32/ebp
13147     5d/pop-to-ebp
13148     c3/return
13149 
13150 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13151     # . prologue
13152     55/push-ebp
13153     89/<- %ebp 4/r32/esp
13154     # . save registers
13155     50/push-eax
13156     # if (l == 0) return
13157     81 7/subop/compare *(ebp+0xc) 0/imm32
13158     74/jump-if-= $emit-subx-rm32:end/disp8
13159     # var v/eax: (addr stmt-var)
13160     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13161     (emit-subx-var-as-rm32 *(ebp+8) %eax)
13162 $emit-subx-rm32:end:
13163     # . restore registers
13164     58/pop-to-eax
13165     # . epilogue
13166     89/<- %esp 5/r32/ebp
13167     5d/pop-to-ebp
13168     c3/return
13169 
13170 get-stmt-operand-from-arg-location:  # stmt: (addr stmt), l: arg-location -> var/eax: (addr stmt-var)
13171     # . prologue
13172     55/push-ebp
13173     89/<- %ebp 4/r32/esp
13174     # . save registers
13175     51/push-ecx
13176     # eax = l
13177     8b/-> *(ebp+0xc) 0/r32/eax
13178     # ecx = stmt
13179     8b/-> *(ebp+8) 1/r32/ecx
13180     # if (l == 1) return stmt->inouts
13181     {
13182       3d/compare-eax-and 1/imm32
13183       75/jump-if-!= break/disp8
13184 $get-stmt-operand-from-arg-location:1:
13185       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13186       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13187     }
13188     # if (l == 2) return stmt->inouts->next
13189     {
13190       3d/compare-eax-and 2/imm32
13191       75/jump-if-!= break/disp8
13192 $get-stmt-operand-from-arg-location:2:
13193       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13194       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13195       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13196     }
13197     # if (l == 3) return stmt->outputs
13198     {
13199       3d/compare-eax-and 3/imm32
13200       75/jump-if-!= break/disp8
13201 $get-stmt-operand-from-arg-location:3:
13202       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13203       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13204     }
13205     # abort
13206     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
13207 $get-stmt-operand-from-arg-location:end:
13208     # . restore registers
13209     59/pop-to-ecx
13210     # . epilogue
13211     89/<- %esp 5/r32/ebp
13212     5d/pop-to-ebp
13213     c3/return
13214 
13215 $get-stmt-operand-from-arg-location:abort:
13216     # error("invalid arg-location " eax)
13217     (write-buffered Stderr "invalid arg-location ")
13218     (print-int32-buffered Stderr %eax)
13219     (write-buffered Stderr Newline)
13220     (flush Stderr)
13221     # . syscall(exit, 1)
13222     bb/copy-to-ebx  1/imm32
13223     b8/copy-to-eax  1/imm32/exit
13224     cd/syscall  0x80/imm8
13225     # never gets here
13226 
13227 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13228     # . prologue
13229     55/push-ebp
13230     89/<- %ebp 4/r32/esp
13231     # . save registers
13232     50/push-eax
13233     51/push-ecx
13234     # if (l == 0) return
13235     81 7/subop/compare *(ebp+0xc) 0/imm32
13236     0f 84/jump-if-= $emit-subx-r32:end/disp32
13237     # var v/eax: (addr stmt-var)
13238     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13239     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13240     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13241     (maybe-get Registers %eax 0xc)  # => eax: (addr register-index)
13242     (write-buffered *(ebp+8) Space)
13243     (print-int32-buffered *(ebp+8) *eax)
13244     (write-buffered *(ebp+8) "/r32")
13245 $emit-subx-r32:end:
13246     # . restore registers
13247     59/pop-to-ecx
13248     58/pop-to-eax
13249     # . epilogue
13250     89/<- %esp 5/r32/ebp
13251     5d/pop-to-ebp
13252     c3/return
13253 
13254 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13255     # . prologue
13256     55/push-ebp
13257     89/<- %ebp 4/r32/esp
13258     # . save registers
13259     50/push-eax
13260     51/push-ecx
13261     # if (l == 0) return
13262     81 7/subop/compare *(ebp+0xc) 0/imm32
13263     0f 84/jump-if-= $emit-subx-imm32:end/disp32
13264     # var v/eax: (handle var)
13265     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13266     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13267     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13268     (write-buffered *(ebp+8) Space)
13269     (write-buffered *(ebp+8) %eax)
13270     (write-buffered *(ebp+8) "/imm32")
13271 $emit-subx-imm32:end:
13272     # . restore registers
13273     59/pop-to-ecx
13274     58/pop-to-eax
13275     # . epilogue
13276     89/<- %esp 5/r32/ebp
13277     5d/pop-to-ebp
13278     c3/return
13279 
13280 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13281     # . prologue
13282     55/push-ebp
13283     89/<- %ebp 4/r32/esp
13284     # . save registers
13285     50/push-eax
13286     51/push-ecx
13287     # if (location == 0) return
13288     81 7/subop/compare *(ebp+0xc) 0/imm32
13289     0f 84/jump-if-= $emit-subx-disp32:end/disp32
13290     # var v/eax: (addr stmt-var)
13291     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13292     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13293     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13294     (write-buffered *(ebp+8) Space)
13295     (write-buffered *(ebp+8) %eax)
13296     # hack: if instruction operation starts with "break", emit ":break"
13297     # var name/ecx: (addr array byte) = lookup(stmt->operation)
13298     8b/-> *(ebp+0x10) 0/r32/eax
13299     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13300     89/<- %ecx 0/r32/eax
13301     {
13302       (string-starts-with? %ecx "break")  # => eax
13303       3d/compare-eax-and 0/imm32/false
13304       74/jump-if-= break/disp8
13305       (write-buffered *(ebp+8) ":break")
13306     }
13307     # hack: if instruction operation starts with "loop", emit ":loop"
13308     {
13309       (string-starts-with? %ecx "loop")  # => eax
13310       3d/compare-eax-and 0/imm32/false
13311       74/jump-if-= break/disp8
13312       (write-buffered *(ebp+8) ":loop")
13313     }
13314     (write-buffered *(ebp+8) "/disp32")
13315 $emit-subx-disp32:end:
13316     # . restore registers
13317     59/pop-to-ecx
13318     58/pop-to-eax
13319     # . epilogue
13320     89/<- %esp 5/r32/ebp
13321     5d/pop-to-ebp
13322     c3/return
13323 
13324 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
13325     # . prologue
13326     55/push-ebp
13327     89/<- %ebp 4/r32/esp
13328     # . save registers
13329     50/push-eax
13330     51/push-ecx
13331     #
13332     (emit-indent *(ebp+8) *Curr-block-depth)
13333     (write-buffered *(ebp+8) "(")
13334     # ecx = stmt
13335     8b/-> *(ebp+0xc) 1/r32/ecx
13336     # - emit function name
13337     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13338     (write-buffered *(ebp+8) %eax)
13339     # - emit arguments
13340     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
13341     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13342     {
13343       # if (curr == null) break
13344       3d/compare-eax-and 0/imm32
13345       74/jump-if-= break/disp8
13346       #
13347       (emit-subx-call-operand *(ebp+8) %eax)
13348       # curr = lookup(curr->next)
13349       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13350       eb/jump loop/disp8
13351     }
13352     #
13353     (write-buffered *(ebp+8) ")\n")
13354 $emit-call:end:
13355     # . restore registers
13356     59/pop-to-ecx
13357     58/pop-to-eax
13358     # . epilogue
13359     89/<- %esp 5/r32/ebp
13360     5d/pop-to-ebp
13361     c3/return
13362 
13363 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
13364     # shares code with emit-subx-var-as-rm32
13365     # . prologue
13366     55/push-ebp
13367     89/<- %ebp 4/r32/esp
13368     # . save registers
13369     50/push-eax
13370     51/push-ecx
13371     56/push-esi
13372     # ecx = s
13373     8b/-> *(ebp+0xc) 1/r32/ecx
13374     # var operand/esi: (addr var) = lookup(s->value)
13375     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13376     89/<- %esi 0/r32/eax
13377     # if (operand->register && !s->is-deref?) emit "%__"
13378     {
13379 $emit-subx-call-operand:check-for-register-direct:
13380       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13381       74/jump-if-= break/disp8
13382       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13383       75/jump-if-!= break/disp8
13384 $emit-subx-call-operand:register-direct:
13385       (write-buffered *(ebp+8) " %")
13386       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13387       (write-buffered *(ebp+8) %eax)
13388       e9/jump $emit-subx-call-operand:end/disp32
13389     }
13390     # else if (operand->register && s->is-deref?) emit "*__"
13391     {
13392 $emit-subx-call-operand:check-for-register-indirect:
13393       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13394       74/jump-if-= break/disp8
13395       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13396       74/jump-if-= break/disp8
13397 $emit-subx-call-operand:register-indirect:
13398       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
13399       e9/jump $emit-subx-call-operand:end/disp32
13400     }
13401     # else if (operand->stack-offset) emit "*(ebp+__)"
13402     {
13403       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
13404       74/jump-if-= break/disp8
13405 $emit-subx-call-operand:stack:
13406       (emit-subx-call-operand-stack *(ebp+8) %esi)
13407       e9/jump $emit-subx-call-operand:end/disp32
13408     }
13409     # else if (operand->type == literal) emit "__"
13410     {
13411       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
13412       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
13413       75/jump-if-!= break/disp8
13414 $emit-subx-call-operand:literal:
13415       (write-buffered *(ebp+8) Space)
13416       (lookup *esi *(esi+4))  # Var-name Var-name => eax
13417       (write-buffered *(ebp+8) %eax)
13418     }
13419 $emit-subx-call-operand:end:
13420     # . restore registers
13421     5e/pop-to-esi
13422     59/pop-to-ecx
13423     58/pop-to-eax
13424     # . epilogue
13425     89/<- %esp 5/r32/ebp
13426     5d/pop-to-ebp
13427     c3/return
13428 
13429 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
13430     # . prologue
13431     55/push-ebp
13432     89/<- %ebp 4/r32/esp
13433     # . save registers
13434     50/push-eax
13435     51/push-ecx
13436     56/push-esi
13437     # esi = v
13438     8b/-> *(ebp+0xc) 6/r32/esi
13439     # var size/ecx: int = size-of-deref(v)
13440     (size-of-deref %esi)  # => eax
13441     89/<- %ecx 0/r32/eax
13442     # var reg-name/esi: (addr array byte) = lookup(v->register)
13443     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13444     89/<- %esi 0/r32/eax
13445     # TODO: assert size is a multiple of 4
13446     # var i/eax: int = 0
13447     b8/copy-to-eax 0/imm32
13448     {
13449 $emit-subx-call-operand-register-indirect:loop:
13450       # if (i >= size) break
13451       39/compare %eax 1/r32/ecx
13452       7d/jump-if->= break/disp8
13453       # emit " *(" v->register "+" i ")"
13454       (write-buffered *(ebp+8) " *(")
13455       (write-buffered *(ebp+8) %esi)
13456       (write-buffered *(ebp+8) "+")
13457       (print-int32-buffered *(ebp+8) %eax)
13458       (write-buffered *(ebp+8) ")")
13459       # i += 4
13460       05/add-to-eax 4/imm32
13461       #
13462       eb/jump loop/disp8
13463     }
13464 $emit-subx-call-operand-register-indirect:end:
13465     # . restore registers
13466     5e/pop-to-esi
13467     59/pop-to-ecx
13468     58/pop-to-eax
13469     # . epilogue
13470     89/<- %esp 5/r32/ebp
13471     5d/pop-to-ebp
13472     c3/return
13473 
13474 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
13475     # . prologue
13476     55/push-ebp
13477     89/<- %ebp 4/r32/esp
13478     # . save registers
13479     50/push-eax
13480     51/push-ecx
13481     56/push-esi
13482     # esi = v
13483     8b/-> *(ebp+0xc) 6/r32/esi
13484     # var curr/ecx: int = v->offset
13485     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
13486     # var max/eax: int = v->offset + size-of(v)
13487     (size-of %esi)  # => eax
13488     # TODO: assert size is a multiple of 4
13489     01/add-to %eax 1/r32/ecx
13490     {
13491 $emit-subx-call-operand-stack:loop:
13492       # if (curr >= max) break
13493       39/compare %ecx 0/r32/eax
13494       7d/jump-if->= break/disp8
13495       # emit " *(ebp+" curr ")"
13496       (write-buffered *(ebp+8) " *(ebp+")
13497       (print-int32-buffered *(ebp+8) %ecx)
13498       (write-buffered *(ebp+8) ")")
13499       # i += 4
13500       81 0/subop/add %ecx 4/imm32
13501       #
13502       eb/jump loop/disp8
13503     }
13504 $emit-subx-call-operand-stack:end:
13505     # . restore registers
13506     5e/pop-to-esi
13507     59/pop-to-ecx
13508     58/pop-to-eax
13509     # . epilogue
13510     89/<- %esp 5/r32/ebp
13511     5d/pop-to-ebp
13512     c3/return
13513 
13514 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
13515     # . prologue
13516     55/push-ebp
13517     89/<- %ebp 4/r32/esp
13518     # . save registers
13519     50/push-eax
13520     51/push-ecx
13521     56/push-esi
13522     # ecx = s
13523     8b/-> *(ebp+0xc) 1/r32/ecx
13524     # var operand/esi: (addr var) = lookup(s->value)
13525     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13526     89/<- %esi 0/r32/eax
13527     # if (operand->register && s->is-deref?) emit "*__"
13528     {
13529 $emit-subx-var-as-rm32:check-for-register-indirect:
13530       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13531       74/jump-if-= break/disp8
13532       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13533       74/jump-if-= break/disp8
13534 $emit-subx-var-as-rm32:register-indirect:
13535       (write-buffered *(ebp+8) " *")
13536       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13537       (write-buffered *(ebp+8) %eax)
13538       e9/jump $emit-subx-var-as-rm32:end/disp32
13539     }
13540     # if (operand->register && !s->is-deref?) emit "%__"
13541     {
13542 $emit-subx-var-as-rm32:check-for-register-direct:
13543       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13544       74/jump-if-= break/disp8
13545       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13546       75/jump-if-!= break/disp8
13547 $emit-subx-var-as-rm32:register-direct:
13548       (write-buffered *(ebp+8) " %")
13549       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13550       (write-buffered *(ebp+8) %eax)
13551       e9/jump $emit-subx-var-as-rm32:end/disp32
13552     }
13553     # else if (operand->stack-offset) emit "*(ebp+__)"
13554     {
13555       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
13556       74/jump-if-= break/disp8
13557 $emit-subx-var-as-rm32:stack:
13558       (write-buffered *(ebp+8) Space)
13559       (write-buffered *(ebp+8) "*(ebp+")
13560       (print-int32-buffered *(ebp+8) *(esi+0x14))  # Var-offset
13561       (write-buffered *(ebp+8) ")")
13562     }
13563 $emit-subx-var-as-rm32:end:
13564     # . restore registers
13565     5e/pop-to-esi
13566     59/pop-to-ecx
13567     58/pop-to-eax
13568     # . epilogue
13569     89/<- %esp 5/r32/ebp
13570     5d/pop-to-ebp
13571     c3/return
13572 
13573 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
13574     # . prologue
13575     55/push-ebp
13576     89/<- %ebp 4/r32/esp
13577     # . save registers
13578     51/push-ecx
13579     # var curr/ecx: (addr primitive) = primitives
13580     8b/-> *(ebp+8) 1/r32/ecx
13581     {
13582 $find-matching-primitive:loop:
13583       # if (curr == null) break
13584       81 7/subop/compare %ecx 0/imm32
13585       0f 84/jump-if-= break/disp32
13586       # if match(curr, stmt) return curr
13587       {
13588         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
13589         3d/compare-eax-and 0/imm32/false
13590         74/jump-if-= break/disp8
13591         89/<- %eax 1/r32/ecx
13592         eb/jump $find-matching-primitive:end/disp8
13593       }
13594 $find-matching-primitive:next-primitive:
13595       # curr = curr->next
13596       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
13597       89/<- %ecx 0/r32/eax
13598       #
13599       e9/jump loop/disp32
13600     }
13601     # return null
13602     b8/copy-to-eax 0/imm32
13603 $find-matching-primitive:end:
13604     # . restore registers
13605     59/pop-to-ecx
13606     # . epilogue
13607     89/<- %esp 5/r32/ebp
13608     5d/pop-to-ebp
13609     c3/return
13610 
13611 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
13612     # A mu stmt matches a primitive if the name matches, all the inout vars
13613     # match, and all the output vars match.
13614     # Vars match if types match and registers match.
13615     # In addition, a stmt output matches a primitive's output if types match
13616     # and the primitive has a wildcard register.
13617     # . prologue
13618     55/push-ebp
13619     89/<- %ebp 4/r32/esp
13620     # . save registers
13621     51/push-ecx
13622     52/push-edx
13623     53/push-ebx
13624     56/push-esi
13625     57/push-edi
13626     # ecx = stmt
13627     8b/-> *(ebp+8) 1/r32/ecx
13628     # edx = primitive
13629     8b/-> *(ebp+0xc) 2/r32/edx
13630     {
13631 $mu-stmt-matches-primitive?:check-name:
13632       # if (primitive->name != stmt->operation) return false
13633       # . var esi: (addr array byte) = lookup(stmt->operation)
13634       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13635       89/<- %esi 0/r32/eax
13636       # . var edi: (addr array byte) = lookup(primitive->name)
13637       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
13638       89/<- %edi 0/r32/eax
13639       (string-equal? %esi %edi)  # => eax
13640       3d/compare-eax-and 0/imm32/false
13641       75/jump-if-!= break/disp8
13642       b8/copy-to-eax 0/imm32
13643       e9/jump $mu-stmt-matches-primitive?:end/disp32
13644     }
13645     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
13646     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13647     89/<- %esi 0/r32/eax
13648     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
13649     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
13650     89/<- %edi 0/r32/eax
13651     {
13652 $mu-stmt-matches-primitive?:inouts-loop:
13653       # if (curr == 0 && curr2 == 0) move on to check outputs
13654       {
13655 $mu-stmt-matches-primitive?:check-both-inouts-null:
13656         81 7/subop/compare %esi 0/imm32
13657         75/jump-if-!= break/disp8
13658 $mu-stmt-matches-primitive?:stmt-inout-null:
13659         81 7/subop/compare %edi 0/imm32
13660         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
13661 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
13662         # return false
13663         b8/copy-to-eax 0/imm32/false
13664         e9/jump $mu-stmt-matches-primitive?:end/disp32
13665       }
13666       # if (curr2 == 0) return false
13667       {
13668 $mu-stmt-matches-primitive?:check-prim-inout-null:
13669         81 7/subop/compare %edi 0/imm32
13670         75/jump-if-!= break/disp8
13671 $mu-stmt-matches-primitive?:prim-inout-null:
13672         b8/copy-to-eax 0/imm32/false
13673         e9/jump $mu-stmt-matches-primitive?:end/disp32
13674       }
13675       # if (curr != curr2) return false
13676       {
13677 $mu-stmt-matches-primitive?:check-inouts-match:
13678         (lookup *edi *(edi+4))  # List-value List-value => eax
13679         (operand-matches-primitive? %esi %eax)  # => eax
13680         3d/compare-eax-and 0/imm32/false
13681         75/jump-if-!= break/disp8
13682 $mu-stmt-matches-primitive?:inouts-match:
13683         b8/copy-to-eax 0/imm32/false
13684         e9/jump $mu-stmt-matches-primitive?:end/disp32
13685       }
13686 $mu-stmt-matches-primitive?:next-inout:
13687       # curr = lookup(curr->next)
13688       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
13689       89/<- %esi 0/r32/eax
13690       # curr2 = lookup(curr2->next)
13691       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
13692       89/<- %edi 0/r32/eax
13693       #
13694       e9/jump loop/disp32
13695     }
13696 $mu-stmt-matches-primitive?:check-outputs:
13697     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
13698     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13699     89/<- %esi 0/r32/eax
13700     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
13701     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
13702     89/<- %edi 0/r32/eax
13703     {
13704 $mu-stmt-matches-primitive?:outputs-loop:
13705       # if (curr == 0) return (curr2 == 0)
13706       {
13707 $mu-stmt-matches-primitive?:check-both-outputs-null:
13708         81 7/subop/compare %esi 0/imm32
13709         75/jump-if-!= break/disp8
13710         {
13711 $mu-stmt-matches-primitive?:stmt-output-null:
13712           81 7/subop/compare %edi 0/imm32
13713           75/jump-if-!= break/disp8
13714 $mu-stmt-matches-primitive?:both-outputs-null:
13715           # return true
13716           b8/copy-to-eax 1/imm32
13717           e9/jump $mu-stmt-matches-primitive?:end/disp32
13718         }
13719 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
13720         # return false
13721         b8/copy-to-eax 0/imm32
13722         e9/jump $mu-stmt-matches-primitive?:end/disp32
13723       }
13724       # if (curr2 == 0) return false
13725       {
13726 $mu-stmt-matches-primitive?:check-prim-output-null:
13727         81 7/subop/compare %edi 0/imm32
13728         75/jump-if-!= break/disp8
13729 $mu-stmt-matches-primitive?:prim-output-is-null:
13730         b8/copy-to-eax 0/imm32
13731         e9/jump $mu-stmt-matches-primitive?:end/disp32
13732       }
13733       # if (curr != curr2) return false
13734       {
13735 $mu-stmt-matches-primitive?:check-outputs-match:
13736         (lookup *edi *(edi+4))  # List-value List-value => eax
13737         (operand-matches-primitive? %esi %eax)  # => eax
13738         3d/compare-eax-and 0/imm32/false
13739         75/jump-if-!= break/disp8
13740 $mu-stmt-matches-primitive?:outputs-match:
13741         b8/copy-to-eax 0/imm32
13742         e9/jump $mu-stmt-matches-primitive?:end/disp32
13743       }
13744 $mu-stmt-matches-primitive?:next-output:
13745       # curr = lookup(curr->next)
13746       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
13747       89/<- %esi 0/r32/eax
13748       # curr2 = lookup(curr2->next)
13749       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
13750       89/<- %edi 0/r32/eax
13751       #
13752       e9/jump loop/disp32
13753     }
13754 $mu-stmt-matches-primitive?:return-true:
13755     b8/copy-to-eax 1/imm32
13756 $mu-stmt-matches-primitive?:end:
13757     # . restore registers
13758     5f/pop-to-edi
13759     5e/pop-to-esi
13760     5b/pop-to-ebx
13761     5a/pop-to-edx
13762     59/pop-to-ecx
13763     # . epilogue
13764     89/<- %esp 5/r32/ebp
13765     5d/pop-to-ebp
13766     c3/return
13767 
13768 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
13769     # . prologue
13770     55/push-ebp
13771     89/<- %ebp 4/r32/esp
13772     # . save registers
13773     51/push-ecx
13774     52/push-edx
13775     53/push-ebx
13776     56/push-esi
13777     57/push-edi
13778     # ecx = s
13779     8b/-> *(ebp+8) 1/r32/ecx
13780     # var var/esi: (addr var) = lookup(s->value)
13781     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13782     89/<- %esi 0/r32/eax
13783     # edi = prim-var
13784     8b/-> *(ebp+0xc) 7/r32/edi
13785 $operand-matches-primitive?:check-type:
13786     # if (var->type != prim-var->type) return false
13787     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
13788     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
13789     89/<- %ebx 0/r32/eax
13790     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
13791     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
13792     (subx-type-equal? %ebx %eax)  # => eax
13793     3d/compare-eax-and 0/imm32/false
13794     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
13795     {
13796 $operand-matches-primitive?:check-register:
13797       # if prim-var is in memory and var is in register but dereference, match
13798       {
13799         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
13800         0f 85/jump-if-!= break/disp32
13801         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13802         74/jump-if-= break/disp8
13803         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13804         74/jump-if-= break/disp8
13805 $operand-matches-primitive?:var-deref-match:
13806         e9/jump $operand-matches-primitive?:return-true/disp32
13807       }
13808       # if prim-var is in register and var is in register but dereference, no match
13809       {
13810         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
13811         0f 84/jump-if-= break/disp32
13812         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13813         0f 84/jump-if-= break/disp32
13814         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13815         74/jump-if-= break/disp8
13816 $operand-matches-primitive?:var-deref-no-match:
13817         e9/jump $operand-matches-primitive?:return-false/disp32
13818       }
13819       # return false if var->register doesn't match prim-var->register
13820       {
13821         # if register addresses are equal, it's a match
13822         # var vreg/ebx: (addr array byte) = lookup(var->register)
13823         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13824         89/<- %ebx 0/r32/eax
13825         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
13826         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13827         89/<- %ecx 0/r32/eax
13828         # if (vreg == preg) break
13829         39/compare %ecx 3/r32/ebx
13830         74/jump-if-= break/disp8
13831 $operand-matches-primitive?:var-register-no-match:
13832         # if either address is 0, return false
13833         81 7/subop/compare %ebx 0/imm32
13834         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
13835         81 7/subop/compare %ecx 0/imm32
13836         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
13837         # if prim-var->register is wildcard, it's a match
13838         (string-equal? %ecx "*")  # Any-register => eax
13839         3d/compare-eax-and 0/imm32/false
13840         75/jump-if-!= break/disp8
13841 $operand-matches-primitive?:wildcard-no-match:
13842         # if string contents aren't equal, return false
13843         (string-equal? %ecx %ebx)  # => eax
13844         3d/compare-eax-and 0/imm32/false
13845         74/jump-if-= $operand-matches-primitive?:return-false/disp8
13846       }
13847     }
13848 $operand-matches-primitive?:return-true:
13849     b8/copy-to-eax 1/imm32/true
13850     eb/jump $operand-matches-primitive?:end/disp8
13851 $operand-matches-primitive?:return-false:
13852     b8/copy-to-eax 0/imm32/false
13853 $operand-matches-primitive?:end:
13854     # . restore registers
13855     5f/pop-to-edi
13856     5e/pop-to-esi
13857     5b/pop-to-ebx
13858     5a/pop-to-edx
13859     59/pop-to-ecx
13860     # . epilogue
13861     89/<- %esp 5/r32/ebp
13862     5d/pop-to-ebp
13863     c3/return
13864 
13865 subx-type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
13866     # . prologue
13867     55/push-ebp
13868     89/<- %ebp 4/r32/esp
13869     # . save registers
13870     51/push-ecx
13871     # var alit/ecx: boolean = is-literal-type?(a)
13872     (is-simple-mu-type? *(ebp+8) 0)  # => eax
13873     89/<- %ecx 0/r32/eax
13874     # var blit/eax: boolean = is-literal-type?(b)
13875     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
13876     # return alit == blit
13877     39/compare %eax 1/r32/ecx
13878     0f 94/set-byte-if-= %al
13879     81 4/subop/and %eax 0xff/imm32
13880 $subx-type-equal?:end:
13881     # . restore registers
13882     59/pop-to-ecx
13883     # . epilogue
13884     89/<- %esp 5/r32/ebp
13885     5d/pop-to-ebp
13886     c3/return
13887 
13888 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
13889     # . prologue
13890     55/push-ebp
13891     89/<- %ebp 4/r32/esp
13892     # . save registers
13893     51/push-ecx
13894     # ecx = n
13895     8b/-> *(ebp+0xc) 1/r32/ecx
13896     # return (a->value == n)
13897     8b/-> *(ebp+8) 0/r32/eax
13898     39/compare *(eax+4) 1/r32/ecx  # Tree-value
13899     0f 94/set-byte-if-= %al
13900     81 4/subop/and %eax 0xff/imm32
13901 $is-simple-mu-type?:end:
13902     # . restore registers
13903     59/pop-to-ecx
13904     # . epilogue
13905     89/<- %esp 5/r32/ebp
13906     5d/pop-to-ebp
13907     c3/return
13908 
13909 test-emit-subx-stmt-primitive:
13910     # Primitive operation on a variable on the stack.
13911     #   increment foo
13912     # =>
13913     #   ff 0/subop/increment *(ebp-8)
13914     #
13915     # There's a variable on the var stack as follows:
13916     #   name: 'foo'
13917     #   type: int
13918     #   stack-offset: -8
13919     #
13920     # There's a primitive with this info:
13921     #   name: 'increment'
13922     #   inouts: int/mem
13923     #   value: 'ff 0/subop/increment'
13924     #
13925     # . prologue
13926     55/push-ebp
13927     89/<- %ebp 4/r32/esp
13928     # setup
13929     (clear-stream _test-output-stream)
13930     (clear-stream $_test-output-buffered-file->buffer)
13931     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
13932 $test-emit-subx-stmt-primitive:initialize-type:
13933     # var type/ecx: (payload tree type-id) = int
13934     68/push 0/imm32/right:null
13935     68/push 0/imm32/right:null
13936     68/push 0/imm32/left:unused
13937     68/push 1/imm32/value:int
13938     68/push 1/imm32/is-atom?:true
13939     68/push 0x11/imm32/alloc-id:fake:payload
13940     89/<- %ecx 4/r32/esp
13941 $test-emit-subx-stmt-primitive:initialize-var:
13942     # var var-foo/ecx: (payload var) = var(type)
13943     68/push 0/imm32/no-register
13944     68/push 0/imm32/no-register
13945     68/push -8/imm32/stack-offset
13946     68/push 1/imm32/block-depth
13947     51/push-ecx/type
13948     68/push 0x11/imm32/alloc-id:fake
13949     68/push 0/imm32/name
13950     68/push 0/imm32/name
13951     68/push 0x11/imm32/alloc-id:fake:payload
13952     89/<- %ecx 4/r32/esp
13953 $test-emit-subx-stmt-primitive:initialize-var-name:
13954     # var-foo->name = "foo"
13955     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
13956     (copy-array Heap "foo" %eax)
13957 $test-emit-subx-stmt-primitive:initialize-stmt-var:
13958     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
13959     68/push 0/imm32/is-deref:false
13960     68/push 0/imm32/next
13961     68/push 0/imm32/next
13962     51/push-ecx/var-foo
13963     68/push 0x11/imm32/alloc-id:fake
13964     68/push 0x11/imm32/alloc-id:fake:payload
13965     89/<- %ebx 4/r32/esp
13966 $test-emit-subx-stmt-primitive:initialize-stmt:
13967     # var stmt/esi: (addr statement)
13968     68/push 0/imm32/no-outputs
13969     68/push 0/imm32/no-outputs
13970     53/push-ebx/inouts
13971     68/push 0x11/imm32/alloc-id:fake
13972     68/push 0/imm32/operation
13973     68/push 0/imm32/operation
13974     68/push 1/imm32/tag
13975     89/<- %esi 4/r32/esp
13976 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
13977     # stmt->operation = "increment"
13978     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
13979     (copy-array Heap "increment" %eax)
13980 $test-emit-subx-stmt-primitive:initialize-primitive:
13981     # var primitives/ebx: (addr primitive)
13982     68/push 0/imm32/next
13983     68/push 0/imm32/next
13984     68/push 0/imm32/output-is-write-only
13985     68/push 0/imm32/no-disp32
13986     68/push 0/imm32/no-imm32
13987     68/push 0/imm32/no-r32
13988     68/push 1/imm32/rm32-is-first-inout
13989     68/push 0/imm32/subx-name
13990     68/push 0/imm32/subx-name
13991     68/push 0/imm32/no-outputs
13992     68/push 0/imm32/no-outputs
13993     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
13994     68/push 0x11/imm32/alloc-id:fake
13995     68/push 0/imm32/name
13996     68/push 0/imm32/name
13997     89/<- %ebx 4/r32/esp
13998 $test-emit-subx-stmt-primitive:initialize-primitive-name:
13999     # primitives->name = "increment"
14000     (copy-array Heap "increment" %ebx)  # Primitive-name
14001 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
14002     # primitives->subx-name = "ff 0/subop/increment"
14003     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14004     (copy-array Heap "ff 0/subop/increment" %eax)
14005     # convert
14006     c7 0/subop/copy *Curr-block-depth 0/imm32
14007     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
14008     (flush _test-output-buffered-file)
14009 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14015     # check output
14016     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
14017     # . epilogue
14018     89/<- %esp 5/r32/ebp
14019     5d/pop-to-ebp
14020     c3/return
14021 
14022 test-emit-subx-stmt-primitive-register:
14023     # Primitive operation on a variable in a register.
14024     #   foo <- increment
14025     # =>
14026     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14027     #
14028     # There's a variable on the var stack as follows:
14029     #   name: 'foo'
14030     #   type: int
14031     #   register: 'eax'
14032     #
14033     # There's a primitive with this info:
14034     #   name: 'increment'
14035     #   out: int/reg
14036     #   value: 'ff 0/subop/increment'
14037     #
14038     # . prologue
14039     55/push-ebp
14040     89/<- %ebp 4/r32/esp
14041     # setup
14042     (clear-stream _test-output-stream)
14043     (clear-stream $_test-output-buffered-file->buffer)
14044 $test-emit-subx-stmt-primitive-register:initialize-type:
14045     # var type/ecx: (payload tree type-id) = int
14046     68/push 0/imm32/right:null
14047     68/push 0/imm32/right:null
14048     68/push 0/imm32/left:unused
14049     68/push 1/imm32/value:int
14050     68/push 1/imm32/is-atom?:true
14051     68/push 0x11/imm32/alloc-id:fake:payload
14052     89/<- %ecx 4/r32/esp
14053 $test-emit-subx-stmt-primitive-register:initialize-var:
14054     # var var-foo/ecx: (payload var)
14055     68/push 0/imm32/register
14056     68/push 0/imm32/register
14057     68/push 0/imm32/no-stack-offset
14058     68/push 1/imm32/block-depth
14059     51/push-ecx
14060     68/push 0x11/imm32/alloc-id:fake
14061     68/push 0/imm32/name
14062     68/push 0/imm32/name
14063     68/push 0x11/imm32/alloc-id:fake:payload
14064     89/<- %ecx 4/r32/esp
14065 $test-emit-subx-stmt-primitive-register:initialize-var-name:
14066     # var-foo->name = "foo"
14067     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14068     (copy-array Heap "foo" %eax)
14069 $test-emit-subx-stmt-primitive-register:initialize-var-register:
14070     # var-foo->register = "eax"
14071     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14072     (copy-array Heap "eax" %eax)
14073 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
14074     # var operand/ebx: (payload stmt-var)
14075     68/push 0/imm32/is-deref:false
14076     68/push 0/imm32/next
14077     68/push 0/imm32/next
14078     51/push-ecx/var-foo
14079     68/push 0x11/imm32/alloc-id:fake
14080     68/push 0x11/imm32/alloc-id:fake:payload
14081     89/<- %ebx 4/r32/esp
14082 $test-emit-subx-stmt-primitive-register:initialize-stmt:
14083     # var stmt/esi: (addr statement)
14084     53/push-ebx/outputs
14085     68/push 0x11/imm32/alloc-id:fake
14086     68/push 0/imm32/no-inouts
14087     68/push 0/imm32/no-inouts
14088     68/push 0/imm32/operation
14089     68/push 0/imm32/operation
14090     68/push 1/imm32
14091     89/<- %esi 4/r32/esp
14092 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
14093     # stmt->operation = "increment"
14094     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14095     (copy-array Heap "increment" %eax)
14096 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
14097     # var formal-var/ebx: (payload var)
14098     68/push 0/imm32/register
14099     68/push 0/imm32/register
14100     68/push 0/imm32/no-stack-offset
14101     68/push 1/imm32/block-depth
14102     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14103     68/push 0x11/imm32/alloc-id:fake
14104     68/push 0/imm32/name
14105     68/push 0/imm32/name
14106     68/push 0x11/imm32/alloc-id:fake:payload
14107     89/<- %ebx 4/r32/esp
14108 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
14109     # formal-var->name = "dummy"
14110     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14111     (copy-array Heap "dummy" %eax)
14112 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
14113     # formal-var->register = "*"
14114     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14115     (copy-array Heap "*" %eax)  # Any-register
14116 $test-emit-subx-stmt-primitive-register:initialize-var-list:
14117     # var formal-outputs/ebx: (payload list var)
14118     68/push 0/imm32/next
14119     68/push 0/imm32/next
14120     53/push-ebx/formal-var
14121     68/push 0x11/imm32/alloc-id:fake
14122     68/push 0x11/imm32/alloc-id:fake:payload
14123     89/<- %ebx 4/r32/esp
14124 $test-emit-subx-stmt-primitive-register:initialize-primitive:
14125     # var primitives/ebx: (addr primitive)
14126     68/push 0/imm32/next
14127     68/push 0/imm32/next
14128     68/push 0/imm32/output-is-write-only
14129     68/push 0/imm32/no-disp32
14130     68/push 0/imm32/no-imm32
14131     68/push 0/imm32/no-r32
14132     68/push 3/imm32/rm32-is-first-output
14133     68/push 0/imm32/subx-name
14134     68/push 0/imm32/subx-name
14135     53/push-ebx/outputs
14136     68/push 0x11/imm32/alloc-id:fake
14137     68/push 0/imm32/no-inouts
14138     68/push 0/imm32/no-inouts
14139     68/push 0/imm32/name
14140     68/push 0/imm32/name
14141     89/<- %ebx 4/r32/esp
14142 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
14143     # primitives->name = "increment"
14144     (copy-array Heap "increment" %ebx)  # Primitive-name
14145 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
14146     # primitives->subx-name = "ff 0/subop/increment"
14147     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14148     (copy-array Heap "ff 0/subop/increment" %eax)
14149     # convert
14150     c7 0/subop/copy *Curr-block-depth 0/imm32
14151     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
14152     (flush _test-output-buffered-file)
14153 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14159     # check output
14160     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
14161     # . epilogue
14162     89/<- %esp 5/r32/ebp
14163     5d/pop-to-ebp
14164     c3/return
14165 
14166 test-emit-subx-stmt-select-primitive:
14167     # Select the right primitive between overloads.
14168     #   foo <- increment
14169     # =>
14170     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14171     #
14172     # There's a variable on the var stack as follows:
14173     #   name: 'foo'
14174     #   type: int
14175     #   register: 'eax'
14176     #
14177     # There's two primitives, as follows:
14178     #   - name: 'increment'
14179     #     out: int/reg
14180     #     value: 'ff 0/subop/increment'
14181     #   - name: 'increment'
14182     #     inout: int/mem
14183     #     value: 'ff 0/subop/increment'
14184     #
14185     # . prologue
14186     55/push-ebp
14187     89/<- %ebp 4/r32/esp
14188     # setup
14189     (clear-stream _test-output-stream)
14190     (clear-stream $_test-output-buffered-file->buffer)
14191 $test-emit-subx-stmt-select-primitive:initialize-type:
14192     # var type/ecx: (payload tree type-id) = int
14193     68/push 0/imm32/right:null
14194     68/push 0/imm32/right:null
14195     68/push 0/imm32/left:unused
14196     68/push 1/imm32/value:int
14197     68/push 1/imm32/is-atom?:true
14198     68/push 0x11/imm32/alloc-id:fake:payload
14199     89/<- %ecx 4/r32/esp
14200 $test-emit-subx-stmt-select-primitive:initialize-var:
14201     # var var-foo/ecx: (payload var)
14202     68/push 0/imm32/register
14203     68/push 0/imm32/register
14204     68/push 0/imm32/no-stack-offset
14205     68/push 1/imm32/block-depth
14206     51/push-ecx
14207     68/push 0x11/imm32/alloc-id:fake
14208     68/push 0/imm32/name
14209     68/push 0/imm32/name
14210     68/push 0x11/imm32/alloc-id:fake:payload
14211     89/<- %ecx 4/r32/esp
14212 $test-emit-subx-stmt-select-primitive:initialize-var-name:
14213     # var-foo->name = "foo"
14214     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14215     (copy-array Heap "foo" %eax)
14216 $test-emit-subx-stmt-select-primitive:initialize-var-register:
14217     # var-foo->register = "eax"
14218     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14219     (copy-array Heap "eax" %eax)
14220 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
14221     # var operand/ebx: (payload stmt-var)
14222     68/push 0/imm32/is-deref:false
14223     68/push 0/imm32/next
14224     68/push 0/imm32/next
14225     51/push-ecx/var-foo
14226     68/push 0x11/imm32/alloc-id:fake
14227     68/push 0x11/imm32/alloc-id:fake:payload
14228     89/<- %ebx 4/r32/esp
14229 $test-emit-subx-stmt-select-primitive:initialize-stmt:
14230     # var stmt/esi: (addr statement)
14231     53/push-ebx/outputs
14232     68/push 0x11/imm32/alloc-id:fake
14233     68/push 0/imm32/no-inouts
14234     68/push 0/imm32/no-inouts
14235     68/push 0/imm32/operation
14236     68/push 0/imm32/operation
14237     68/push 1/imm32
14238     89/<- %esi 4/r32/esp
14239 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
14240     # stmt->operation = "increment"
14241     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14242     (copy-array Heap "increment" %eax)
14243 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
14244     # var formal-var/ebx: (payload var)
14245     68/push 0/imm32/register
14246     68/push 0/imm32/register
14247     68/push 0/imm32/no-stack-offset
14248     68/push 1/imm32/block-depth
14249     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14250     68/push 0x11/imm32/alloc-id:fake
14251     68/push 0/imm32/name
14252     68/push 0/imm32/name
14253     68/push 0x11/imm32/alloc-id:fake:payload
14254     89/<- %ebx 4/r32/esp
14255 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
14256     # formal-var->name = "dummy"
14257     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14258     (copy-array Heap "dummy" %eax)
14259 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
14260     # formal-var->register = "*"
14261     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14262     (copy-array Heap "*" %eax)  # Any-register
14263 $test-emit-subx-stmt-select-primitive:initialize-var-list:
14264     # var formal-outputs/ebx: (payload list var)
14265     68/push 0/imm32/next
14266     68/push 0/imm32/next
14267     53/push-ebx/formal-var
14268     68/push 0x11/imm32/alloc-id:fake
14269     68/push 0x11/imm32/alloc-id:fake:payload
14270     89/<- %ebx 4/r32/esp
14271 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
14272     # var primitive2/edi: (payload primitive)
14273     68/push 0/imm32/next
14274     68/push 0/imm32/next
14275     68/push 0/imm32/output-is-write-only
14276     68/push 0/imm32/no-disp32
14277     68/push 0/imm32/no-imm32
14278     68/push 0/imm32/no-r32
14279     68/push 3/imm32/rm32-is-first-output
14280     68/push 0/imm32/subx-name
14281     68/push 0/imm32/subx-name
14282     53/push-ebx/outputs
14283     68/push 0x11/imm32/alloc-id:fake
14284     68/push 0/imm32/no-inouts
14285     68/push 0/imm32/no-inouts
14286     68/push 0/imm32/name
14287     68/push 0/imm32/name
14288     68/push 0x11/imm32/alloc-id:fake:payload
14289     89/<- %edi 4/r32/esp
14290 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
14291     # primitives->name = "increment"
14292     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
14293     (copy-array Heap "increment" %eax)
14294 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
14295     # primitives->subx-name = "ff 0/subop/increment"
14296     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
14297     (copy-array Heap "ff 0/subop/increment" %eax)
14298 $test-emit-subx-stmt-select-primitive:initialize-primitive:
14299     # var primitives/ebx: (addr primitive)
14300     57/push-edi
14301     68/push 0x11/imm32/alloc-id:fake
14302     68/push 0/imm32/output-is-write-only
14303     68/push 0/imm32/no-disp32
14304     68/push 0/imm32/no-imm32
14305     68/push 0/imm32/no-r32
14306     68/push 1/imm32/rm32-is-first-inout
14307     68/push 0/imm32/subx-name
14308     68/push 0/imm32/subx-name
14309     68/push 0/imm32/no-outputs
14310     68/push 0/imm32/no-outputs
14311     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14312     68/push 0x11/imm32/alloc-id:fake
14313     68/push 0/imm32/name
14314     68/push 0/imm32/name
14315     89/<- %ebx 4/r32/esp
14316 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
14317     # primitives->name = "increment"
14318     (copy-array Heap "increment" %ebx)  # Primitive-name
14319 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
14320     # primitives->subx-name = "ff 0/subop/increment"
14321     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14322     (copy-array Heap "ff 0/subop/increment" %eax)
14323     # convert
14324     c7 0/subop/copy *Curr-block-depth 0/imm32
14325     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
14326     (flush _test-output-buffered-file)
14327 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14333     # check output
14334     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
14335     # . epilogue
14336     89/<- %esp 5/r32/ebp
14337     5d/pop-to-ebp
14338     c3/return
14339 
14340 test-emit-subx-stmt-select-primitive-2:
14341     # Select the right primitive between overloads.
14342     #   increment foo
14343     # =>
14344     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14345     #
14346     # There's a variable on the var stack as follows:
14347     #   name: 'foo'
14348     #   type: int
14349     #   register: 'eax'
14350     #
14351     # There's two primitives, as follows:
14352     #   - name: 'increment'
14353     #     out: int/reg
14354     #     value: 'ff 0/subop/increment'
14355     #   - name: 'increment'
14356     #     inout: int/mem
14357     #     value: 'ff 0/subop/increment'
14358     #
14359     # . prologue
14360     55/push-ebp
14361     89/<- %ebp 4/r32/esp
14362     # setup
14363     (clear-stream _test-output-stream)
14364     (clear-stream $_test-output-buffered-file->buffer)
14365 $test-emit-subx-stmt-select-primitive-2:initialize-type:
14366     # var type/ecx: (payload tree type-id) = int
14367     68/push 0/imm32/right:null
14368     68/push 0/imm32/right:null
14369     68/push 0/imm32/left:unused
14370     68/push 1/imm32/value:int
14371     68/push 1/imm32/is-atom?:true
14372     68/push 0x11/imm32/alloc-id:fake:payload
14373     89/<- %ecx 4/r32/esp
14374 $test-emit-subx-stmt-select-primitive-2:initialize-var:
14375     # var var-foo/ecx: (payload var)
14376     68/push 0/imm32/register
14377     68/push 0/imm32/register
14378     68/push 0/imm32/no-stack-offset
14379     68/push 1/imm32/block-depth
14380     51/push-ecx
14381     68/push 0x11/imm32/alloc-id:fake
14382     68/push 0/imm32/name
14383     68/push 0/imm32/name
14384     68/push 0x11/imm32/alloc-id:fake:payload
14385     89/<- %ecx 4/r32/esp
14386 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
14387     # var-foo->name = "foo"
14388     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14389     (copy-array Heap "foo" %eax)
14390 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
14391     # var-foo->register = "eax"
14392     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14393     (copy-array Heap "eax" %eax)
14394 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
14395     # var operand/ebx: (payload stmt-var)
14396     68/push 0/imm32/is-deref:false
14397     68/push 0/imm32/next
14398     68/push 0/imm32/next
14399     51/push-ecx/var-foo
14400     68/push 0x11/imm32/alloc-id:fake
14401     68/push 0x11/imm32/alloc-id:fake:payload
14402     89/<- %ebx 4/r32/esp
14403 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
14404     # var stmt/esi: (addr statement)
14405     68/push 0/imm32/no-outputs
14406     68/push 0/imm32/no-outputs
14407     53/push-ebx/inouts
14408     68/push 0x11/imm32/alloc-id:fake
14409     68/push 0/imm32/operation
14410     68/push 0/imm32/operation
14411     68/push 1/imm32
14412     89/<- %esi 4/r32/esp
14413 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
14414     # stmt->operation = "increment"
14415     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14416     (copy-array Heap "increment" %eax)
14417 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
14418     # var formal-var/ebx: (payload var)
14419     68/push 0/imm32/register
14420     68/push 0/imm32/register
14421     68/push 0/imm32/no-stack-offset
14422     68/push 1/imm32/block-depth
14423     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14424     68/push 0x11/imm32/alloc-id:fake
14425     68/push 0/imm32/name
14426     68/push 0/imm32/name
14427     68/push 0x11/imm32/alloc-id:fake:payload
14428     89/<- %ebx 4/r32/esp
14429 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
14430     # formal-var->name = "dummy"
14431     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14432     (copy-array Heap "dummy" %eax)
14433 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
14434     # formal-var->register = "*"
14435     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14436     (copy-array Heap "*" %eax)  # Any-register
14437 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
14438     # var formal-outputs/ebx: (payload list stmt-var)
14439     68/push 0/imm32/next
14440     68/push 0/imm32/next
14441     53/push-ebx/formal-var
14442     68/push 0x11/imm32/alloc-id:fake
14443     68/push 0x11/imm32/alloc-id:fake:payload
14444     89/<- %ebx 4/r32/esp
14445 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
14446     # var primitive2/edi: (payload primitive)
14447     68/push 0/imm32/next
14448     68/push 0/imm32/next
14449     68/push 0/imm32/output-is-write-only
14450     68/push 0/imm32/no-disp32
14451     68/push 0/imm32/no-imm32
14452     68/push 0/imm32/no-r32
14453     68/push 3/imm32/rm32-is-first-output
14454     68/push 0/imm32/subx-name
14455     68/push 0/imm32/subx-name
14456     53/push-ebx/outputs
14457     68/push 0x11/imm32/alloc-id:fake
14458     68/push 0/imm32/no-inouts
14459     68/push 0/imm32/no-inouts
14460     68/push 0/imm32/name
14461     68/push 0/imm32/name
14462     68/push 0x11/imm32/alloc-id:fake:payload
14463     89/<- %edi 4/r32/esp
14464 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
14465     # primitives->name = "increment"
14466     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
14467     (copy-array Heap "increment" %eax)
14468 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
14469     # primitives->subx-name = "ff 0/subop/increment"
14470     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
14471     (copy-array Heap "ff 0/subop/increment" %eax)
14472 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
14473     # var primitives/ebx: (addr primitive)
14474     57/push-edi
14475     68/push 0x11/imm32/alloc-id:fake
14476     68/push 0/imm32/output-is-write-only
14477     68/push 0/imm32/no-disp32
14478     68/push 0/imm32/no-imm32
14479     68/push 0/imm32/no-r32
14480     68/push 1/imm32/rm32-is-first-inout
14481     68/push 0/imm32/subx-name
14482     68/push 0/imm32/subx-name
14483     68/push 0/imm32/no-outputs
14484     68/push 0/imm32/no-outputs
14485     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14486     68/push 0x11/imm32/alloc-id:fake
14487     68/push 0/imm32/name
14488     68/push 0/imm32/name
14489     89/<- %ebx 4/r32/esp
14490 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
14491     # primitives->name = "increment"
14492     (copy-array Heap "increment" %ebx)  # Primitive-name
14493 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
14494     # primitives->subx-name = "ff 0/subop/increment"
14495     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14496     (copy-array Heap "ff 0/subop/increment" %eax)
14497     # convert
14498     c7 0/subop/copy *Curr-block-depth 0/imm32
14499     (emit-subx-stmt _test-output-buffered-file %esi %ebx)
14500     (flush _test-output-buffered-file)
14501 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14507     # check output
14508     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
14509     # . epilogue
14510     89/<- %esp 5/r32/ebp
14511     5d/pop-to-ebp
14512     c3/return
14513 
14514 test-increment-register:
14515     # Select the right register between overloads.
14516     #   foo <- increment
14517     # =>
14518     #   50/increment-eax
14519     #
14520     # There's a variable on the var stack as follows:
14521     #   name: 'foo'
14522     #   type: int
14523     #   register: 'eax'
14524     #
14525     # Primitives are the global definitions.
14526     #
14527     # . prologue
14528     55/push-ebp
14529     89/<- %ebp 4/r32/esp
14530     # setup
14531     (clear-stream _test-output-stream)
14532     (clear-stream $_test-output-buffered-file->buffer)
14533 $test-increment-register:initialize-type:
14534     # var type/ecx: (payload tree type-id) = int
14535     68/push 0/imm32/right:null
14536     68/push 0/imm32/right:null
14537     68/push 0/imm32/left:unused
14538     68/push 1/imm32/value:int
14539     68/push 1/imm32/is-atom?:true
14540     68/push 0x11/imm32/alloc-id:fake:payload
14541     89/<- %ecx 4/r32/esp
14542 $test-increment-register:initialize-var:
14543     # var var-foo/ecx: (payload var)
14544     68/push 0/imm32/register
14545     68/push 0/imm32/register
14546     68/push 0/imm32/no-stack-offset
14547     68/push 1/imm32/block-depth
14548     51/push-ecx
14549     68/push 0x11/imm32/alloc-id:fake
14550     68/push 0/imm32/name
14551     68/push 0/imm32/name
14552     68/push 0x11/imm32/alloc-id:fake:payload
14553     89/<- %ecx 4/r32/esp
14554 $test-increment-register:initialize-var-name:
14555     # var-foo->name = "foo"
14556     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14557     (copy-array Heap "foo" %eax)
14558 $test-increment-register:initialize-var-register:
14559     # var-foo->register = "eax"
14560     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14561     (copy-array Heap "eax" %eax)
14562 $test-increment-register:initialize-stmt-var:
14563     # var operand/ebx: (payload stmt-var)
14564     68/push 0/imm32/is-deref:false
14565     68/push 0/imm32/next
14566     68/push 0/imm32/next
14567     51/push-ecx/var-foo
14568     68/push 0x11/imm32/alloc-id:fake
14569     68/push 0x11/imm32/alloc-id:fake:payload
14570     89/<- %ebx 4/r32/esp
14571 $test-increment-register:initialize-stmt:
14572     # var stmt/esi: (addr statement)
14573     53/push-ebx/outputs
14574     68/push 0x11/imm32/alloc-id:fake
14575     68/push 0/imm32/no-inouts
14576     68/push 0/imm32/no-inouts
14577     68/push 0/imm32/operation
14578     68/push 0/imm32/operation
14579     68/push 1/imm32
14580     89/<- %esi 4/r32/esp
14581 $test-increment-register:initialize-stmt-operation:
14582     # stmt->operation = "increment"
14583     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14584     (copy-array Heap "increment" %eax)
14585     # convert
14586     c7 0/subop/copy *Curr-block-depth 0/imm32
14587     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14588     (flush _test-output-buffered-file)
14589 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14595     # check output
14596     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
14597     # . epilogue
14598     89/<- %esp 5/r32/ebp
14599     5d/pop-to-ebp
14600     c3/return
14601 
14602 test-add-reg-to-reg:
14603     #   var1/reg <- add var2/reg
14604     # =>
14605     #   01/add-to %var1 var2
14606     #
14607     # . prologue
14608     55/push-ebp
14609     89/<- %ebp 4/r32/esp
14610     # setup
14611     (clear-stream _test-output-stream)
14612     (clear-stream $_test-output-buffered-file->buffer)
14613 $test-add-reg-to-reg:initialize-type:
14614     # var type/ecx: (payload tree type-id) = int
14615     68/push 0/imm32/right:null
14616     68/push 0/imm32/right:null
14617     68/push 0/imm32/left:unused
14618     68/push 1/imm32/value:int
14619     68/push 1/imm32/is-atom?:true
14620     68/push 0x11/imm32/alloc-id:fake:payload
14621     89/<- %ecx 4/r32/esp
14622 $test-add-reg-to-reg:initialize-var1:
14623     # var var1/ecx: (payload var)
14624     68/push 0/imm32/register
14625     68/push 0/imm32/register
14626     68/push 0/imm32/no-stack-offset
14627     68/push 1/imm32/block-depth
14628     51/push-ecx
14629     68/push 0x11/imm32/alloc-id:fake
14630     68/push 0/imm32/name
14631     68/push 0/imm32/name
14632     68/push 0x11/imm32/alloc-id:fake:payload
14633     89/<- %ecx 4/r32/esp
14634 $test-add-reg-to-reg:initialize-var1-name:
14635     # var1->name = "var1"
14636     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14637     (copy-array Heap "var1" %eax)
14638 $test-add-reg-to-reg:initialize-var1-register:
14639     # var1->register = "eax"
14640     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14641     (copy-array Heap "eax" %eax)
14642 $test-add-reg-to-reg:initialize-var2:
14643     # var var2/edx: (payload var)
14644     68/push 0/imm32/register
14645     68/push 0/imm32/register
14646     68/push 0/imm32/no-stack-offset
14647     68/push 1/imm32/block-depth
14648     ff 6/subop/push *(ecx+0x10)
14649     68/push 0x11/imm32/alloc-id:fake
14650     68/push 0/imm32/name
14651     68/push 0/imm32/name
14652     68/push 0x11/imm32/alloc-id:fake:payload
14653     89/<- %edx 4/r32/esp
14654 $test-add-reg-to-reg:initialize-var2-name:
14655     # var2->name = "var2"
14656     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14657     (copy-array Heap "var2" %eax)
14658 $test-add-reg-to-reg:initialize-var2-register:
14659     # var2->register = "ecx"
14660     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14661     (copy-array Heap "ecx" %eax)
14662 $test-add-reg-to-reg:initialize-inouts:
14663     # var inouts/esi: (payload stmt-var) = [var2]
14664     68/push 0/imm32/is-deref:false
14665     68/push 0/imm32/next
14666     68/push 0/imm32/next
14667     52/push-edx/var2
14668     68/push 0x11/imm32/alloc-id:fake
14669     68/push 0x11/imm32/alloc-id:fake:payload
14670     89/<- %esi 4/r32/esp
14671 $test-add-reg-to-reg:initialize-outputs:
14672     # var outputs/edi: (payload stmt-var) = [var1]
14673     68/push 0/imm32/is-deref:false
14674     68/push 0/imm32/next
14675     68/push 0/imm32/next
14676     51/push-ecx/var1
14677     68/push 0x11/imm32/alloc-id:fake
14678     68/push 0x11/imm32/alloc-id:fake:payload
14679     89/<- %edi 4/r32/esp
14680 $test-add-reg-to-reg:initialize-stmt:
14681     # var stmt/esi: (addr statement)
14682     68/push 0/imm32/next
14683     68/push 0/imm32/next
14684     57/push-edi/outputs
14685     68/push 0x11/imm32/alloc-id:fake
14686     56/push-esi/inouts
14687     68/push 0x11/imm32/alloc-id:fake
14688     68/push 0/imm32/operation
14689     68/push 0/imm32/operation
14690     68/push 1/imm32/tag:stmt1
14691     89/<- %esi 4/r32/esp
14692 $test-add-reg-to-reg:initialize-stmt-operation:
14693     # stmt->operation = "add"
14694     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14695     (copy-array Heap "add" %eax)
14696     # convert
14697     c7 0/subop/copy *Curr-block-depth 0/imm32
14698     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14699     (flush _test-output-buffered-file)
14700 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14706     # check output
14707     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
14708     # . epilogue
14709     89/<- %esp 5/r32/ebp
14710     5d/pop-to-ebp
14711     c3/return
14712 
14713 test-add-reg-to-mem:
14714     #   add-to var1 var2/reg
14715     # =>
14716     #   01/add-to *(ebp+__) var2
14717     #
14718     # . prologue
14719     55/push-ebp
14720     89/<- %ebp 4/r32/esp
14721     # setup
14722     (clear-stream _test-output-stream)
14723     (clear-stream $_test-output-buffered-file->buffer)
14724 $test-add-reg-to-mem:initialize-type:
14725     # var type/ecx: (payload tree type-id) = int
14726     68/push 0/imm32/right:null
14727     68/push 0/imm32/right:null
14728     68/push 0/imm32/left:unused
14729     68/push 1/imm32/value:int
14730     68/push 1/imm32/is-atom?:true
14731     68/push 0x11/imm32/alloc-id:fake:payload
14732     89/<- %ecx 4/r32/esp
14733 $test-add-reg-to-mem:initialize-var1:
14734     # var var1/ecx: (payload var)
14735     68/push 0/imm32/register
14736     68/push 0/imm32/register
14737     68/push 8/imm32/stack-offset
14738     68/push 1/imm32/block-depth
14739     51/push-ecx
14740     68/push 0x11/imm32/alloc-id:fake
14741     68/push 0/imm32/name
14742     68/push 0/imm32/name
14743     68/push 0x11/imm32/alloc-id:fake:payload
14744     89/<- %ecx 4/r32/esp
14745 $test-add-reg-to-mem:initialize-var1-name:
14746     # var1->name = "var1"
14747     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14748     (copy-array Heap "var1" %eax)
14749 $test-add-reg-to-mem:initialize-var2:
14750     # var var2/edx: (payload var)
14751     68/push 0/imm32/register
14752     68/push 0/imm32/register
14753     68/push 0/imm32/no-stack-offset
14754     68/push 1/imm32/block-depth
14755     ff 6/subop/push *(ecx+0x10)
14756     68/push 0x11/imm32/alloc-id:fake
14757     68/push 0/imm32/name
14758     68/push 0/imm32/name
14759     68/push 0x11/imm32/alloc-id:fake:payload
14760     89/<- %edx 4/r32/esp
14761 $test-add-reg-to-mem:initialize-var2-name:
14762     # var2->name = "var2"
14763     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14764     (copy-array Heap "var2" %eax)
14765 $test-add-reg-to-mem:initialize-var2-register:
14766     # var2->register = "ecx"
14767     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14768     (copy-array Heap "ecx" %eax)
14769 $test-add-reg-to-mem:initialize-inouts:
14770     # var inouts/esi: (payload stmt-var) = [var2]
14771     68/push 0/imm32/is-deref:false
14772     68/push 0/imm32/next
14773     68/push 0/imm32/next
14774     52/push-edx/var2
14775     68/push 0x11/imm32/alloc-id:fake
14776     68/push 0x11/imm32/alloc-id:fake:payload
14777     89/<- %esi 4/r32/esp
14778     # inouts = [var1, var2]
14779     68/push 0/imm32/is-deref:false
14780     56/push-esi/next
14781     68/push 0x11/imm32/alloc-id:fake
14782     51/push-ecx/var1
14783     68/push 0x11/imm32/alloc-id:fake
14784     68/push 0x11/imm32/alloc-id:fake:payload
14785     89/<- %esi 4/r32/esp
14786 $test-add-reg-to-mem:initialize-stmt:
14787     # var stmt/esi: (addr statement)
14788     68/push 0/imm32/next
14789     68/push 0/imm32/next
14790     68/push 0/imm32/outputs
14791     68/push 0/imm32/outputs
14792     56/push-esi/inouts
14793     68/push 0x11/imm32/alloc-id:fake
14794     68/push 0/imm32/operation
14795     68/push 0/imm32/operation
14796     68/push 1/imm32/tag:stmt1
14797     89/<- %esi 4/r32/esp
14798 $test-add-reg-to-mem:initialize-stmt-operation:
14799     # stmt->operation = "add-to"
14800     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14801     (copy-array Heap "add-to" %eax)
14802     # convert
14803     c7 0/subop/copy *Curr-block-depth 0/imm32
14804     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14805     (flush _test-output-buffered-file)
14806 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14812     # check output
14813     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
14814     # . epilogue
14815     89/<- %esp 5/r32/ebp
14816     5d/pop-to-ebp
14817     c3/return
14818 
14819 test-add-mem-to-reg:
14820     #   var1/reg <- add var2
14821     # =>
14822     #   03/add *(ebp+__) var1
14823     #
14824     # . prologue
14825     55/push-ebp
14826     89/<- %ebp 4/r32/esp
14827     # setup
14828     (clear-stream _test-output-stream)
14829     (clear-stream $_test-output-buffered-file->buffer)
14830 $test-add-mem-to-reg:initialize-type:
14831     # var type/ecx: (payload tree type-id) = int
14832     68/push 0/imm32/right:null
14833     68/push 0/imm32/right:null
14834     68/push 0/imm32/left:unused
14835     68/push 1/imm32/value:int
14836     68/push 1/imm32/is-atom?:true
14837     68/push 0x11/imm32/alloc-id:fake:payload
14838     89/<- %ecx 4/r32/esp
14839 $test-add-mem-to-reg:initialize-var:
14840     # var var1/ecx: (payload var)
14841     68/push 0/imm32/register
14842     68/push 0/imm32/register
14843     68/push 0/imm32/no-stack-offset
14844     68/push 1/imm32/block-depth
14845     51/push-ecx
14846     68/push 0x11/imm32/alloc-id:fake
14847     68/push 0/imm32/name
14848     68/push 0/imm32/name
14849     68/push 0x11/imm32/alloc-id:fake:payload
14850     89/<- %ecx 4/r32/esp
14851 $test-add-mem-to-reg:initialize-var-name:
14852     # var1->name = "foo"
14853     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14854     (copy-array Heap "var1" %eax)
14855 $test-add-mem-to-reg:initialize-var-register:
14856     # var1->register = "eax"
14857     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14858     (copy-array Heap "eax" %eax)
14859 $test-add-mem-to-reg:initialize-var2:
14860     # var var2/edx: (payload var)
14861     68/push 0/imm32/register
14862     68/push 0/imm32/register
14863     68/push 8/imm32/stack-offset
14864     68/push 1/imm32/block-depth
14865     ff 6/subop/push *(ecx+0x10)
14866     68/push 0x11/imm32/alloc-id:fake
14867     68/push 0/imm32/name
14868     68/push 0/imm32/name
14869     68/push 0x11/imm32/alloc-id:fake:payload
14870     89/<- %edx 4/r32/esp
14871 $test-add-mem-to-reg:initialize-var2-name:
14872     # var2->name = "var2"
14873     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14874     (copy-array Heap "var2" %eax)
14875 $test-add-mem-to-reg:initialize-inouts:
14876     # var inouts/esi: (payload stmt-var) = [var2]
14877     68/push 0/imm32/is-deref:false
14878     68/push 0/imm32/next
14879     68/push 0/imm32/next
14880     52/push-edx/var2
14881     68/push 0x11/imm32/alloc-id:fake
14882     68/push 0x11/imm32/alloc-id:fake:payload
14883     89/<- %esi 4/r32/esp
14884 $test-add-mem-to-reg:initialize-outputs:
14885     # var outputs/edi: (payload stmt-var) = [var1]
14886     68/push 0/imm32/is-deref:false
14887     68/push 0/imm32/next
14888     68/push 0/imm32/next
14889     51/push-ecx/var1
14890     68/push 0x11/imm32/alloc-id:fake
14891     68/push 0x11/imm32/alloc-id:fake:payload
14892     89/<- %edi 4/r32/esp
14893 $test-add-mem-to-reg:initialize-stmt:
14894     # var stmt/esi: (addr statement)
14895     68/push 0/imm32/next
14896     68/push 0/imm32/next
14897     57/push-edi/outputs
14898     68/push 0x11/imm32/alloc-id:fake
14899     56/push-esi/inouts
14900     68/push 0x11/imm32/alloc-id:fake
14901     68/push 0/imm32/operation
14902     68/push 0/imm32/operation
14903     68/push 1/imm32/tag:stmt1
14904     89/<- %esi 4/r32/esp
14905 $test-add-mem-to-reg:initialize-stmt-operation:
14906     # stmt->operation = "add"
14907     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14908     (copy-array Heap "add" %eax)
14909     # convert
14910     c7 0/subop/copy *Curr-block-depth 0/imm32
14911     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
14912     (flush _test-output-buffered-file)
14913 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
14919     # check output
14920     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
14921     # . epilogue
14922     89/<- %esp 5/r32/ebp
14923     5d/pop-to-ebp
14924     c3/return
14925 
14926 test-add-literal-to-eax:
14927     #   var1/eax <- add 0x34
14928     # =>
14929     #   05/add-to-eax 0x34/imm32
14930     #
14931     # . prologue
14932     55/push-ebp
14933     89/<- %ebp 4/r32/esp
14934     # setup
14935     (clear-stream _test-output-stream)
14936     (clear-stream $_test-output-buffered-file->buffer)
14937 $test-add-literal-to-eax:initialize-var-type:
14938     # var type/ecx: (payload tree type-id) = int
14939     68/push 0/imm32/right:null
14940     68/push 0/imm32/right:null
14941     68/push 0/imm32/left:unused
14942     68/push 1/imm32/value:int
14943     68/push 1/imm32/is-atom?:true
14944     68/push 0x11/imm32/alloc-id:fake:payload
14945     89/<- %ecx 4/r32/esp
14946 $test-add-literal-to-eax:initialize-var:
14947     # var v/ecx: (payload var)
14948     68/push 0/imm32/register
14949     68/push 0/imm32/register
14950     68/push 0/imm32/no-stack-offset
14951     68/push 1/imm32/block-depth
14952     51/push-ecx
14953     68/push 0x11/imm32/alloc-id:fake
14954     68/push 0/imm32/name
14955     68/push 0/imm32/name
14956     68/push 0x11/imm32/alloc-id:fake:payload
14957     89/<- %ecx 4/r32/esp
14958 $test-add-literal-to-eax:initialize-var-name:
14959     # v->name = "v"
14960     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14961     (copy-array Heap "v" %eax)
14962 $test-add-literal-to-eax:initialize-var-register:
14963     # v->register = "eax"
14964     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14965     (copy-array Heap "eax" %eax)
14966 $test-add-literal-to-eax:initialize-literal-type:
14967     # var type/edx: (payload tree type-id) = literal
14968     68/push 0/imm32/right:null
14969     68/push 0/imm32/right:null
14970     68/push 0/imm32/left:unused
14971     68/push 0/imm32/value:literal
14972     68/push 1/imm32/is-atom?:true
14973     68/push 0x11/imm32/alloc-id:fake:payload
14974     89/<- %edx 4/r32/esp
14975 $test-add-literal-to-eax:initialize-literal:
14976     # var l/edx: (payload var)
14977     68/push 0/imm32/register
14978     68/push 0/imm32/register
14979     68/push 0/imm32/no-stack-offset
14980     68/push 1/imm32/block-depth
14981     52/push-edx
14982     68/push 0x11/imm32/alloc-id:fake
14983     68/push 0/imm32/name
14984     68/push 0/imm32/name
14985     68/push 0x11/imm32/alloc-id:fake:payload
14986     89/<- %edx 4/r32/esp
14987 $test-add-literal-to-eax:initialize-literal-value:
14988     # l->name = "0x34"
14989     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14990     (copy-array Heap "0x34" %eax)
14991 $test-add-literal-to-eax:initialize-inouts:
14992     # var inouts/esi: (payload stmt-var) = [l]
14993     68/push 0/imm32/is-deref:false
14994     68/push 0/imm32/next
14995     68/push 0/imm32/next
14996     52/push-edx/l
14997     68/push 0x11/imm32/alloc-id:fake
14998     68/push 0x11/imm32/alloc-id:fake:payload
14999     89/<- %esi 4/r32/esp
15000 $test-add-literal-to-eax:initialize-outputs:
15001     # var outputs/edi: (payload stmt-var) = [v]
15002     68/push 0/imm32/is-deref:false
15003     68/push 0/imm32/next
15004     68/push 0/imm32/next
15005     51/push-ecx/v
15006     68/push 0x11/imm32/alloc-id:fake
15007     68/push 0x11/imm32/alloc-id:fake:payload
15008     89/<- %edi 4/r32/esp
15009 $test-add-literal-to-eax:initialize-stmt:
15010     # var stmt/esi: (addr statement)
15011     68/push 0/imm32/next
15012     68/push 0/imm32/next
15013     57/push-edi/outputs
15014     68/push 0x11/imm32/alloc-id:fake
15015     56/push-esi/inouts
15016     68/push 0x11/imm32/alloc-id:fake
15017     68/push 0/imm32/operation
15018     68/push 0/imm32/operation
15019     68/push 1/imm32/tag:stmt1
15020     89/<- %esi 4/r32/esp
15021 $test-add-literal-to-eax:initialize-stmt-operation:
15022     # stmt->operation = "add"
15023     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15024     (copy-array Heap "add" %eax)
15025     # convert
15026     c7 0/subop/copy *Curr-block-depth 0/imm32
15027     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15028     (flush _test-output-buffered-file)
15029 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15035     # check output
15036     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
15037     # . epilogue
15038     89/<- %esp 5/r32/ebp
15039     5d/pop-to-ebp
15040     c3/return
15041 
15042 test-add-literal-to-reg:
15043     #   var1/ecx <- add 0x34
15044     # =>
15045     #   81 0/subop/add %ecx 0x34/imm32
15046     #
15047     # . prologue
15048     55/push-ebp
15049     89/<- %ebp 4/r32/esp
15050     # setup
15051     (clear-stream _test-output-stream)
15052     (clear-stream $_test-output-buffered-file->buffer)
15053 $test-add-literal-to-reg:initialize-var-type:
15054     # var type/ecx: (payload tree type-id) = int
15055     68/push 0/imm32/right:null
15056     68/push 0/imm32/right:null
15057     68/push 0/imm32/left:unused
15058     68/push 1/imm32/value:int
15059     68/push 1/imm32/is-atom?:true
15060     68/push 0x11/imm32/alloc-id:fake:payload
15061     89/<- %ecx 4/r32/esp
15062 $test-add-literal-to-reg:initialize-var:
15063     # var v/ecx: (payload var)
15064     68/push 0/imm32/register
15065     68/push 0/imm32/register
15066     68/push 0/imm32/no-stack-offset
15067     68/push 1/imm32/block-depth
15068     51/push-ecx
15069     68/push 0x11/imm32/alloc-id:fake
15070     68/push 0/imm32/name
15071     68/push 0/imm32/name
15072     68/push 0x11/imm32/alloc-id:fake:payload
15073     89/<- %ecx 4/r32/esp
15074 $test-add-literal-to-reg:initialize-var-name:
15075     # v->name = "v"
15076     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15077     (copy-array Heap "v" %eax)
15078 $test-add-literal-to-reg:initialize-var-register:
15079     # v->register = "ecx"
15080     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15081     (copy-array Heap "ecx" %eax)
15082 $test-add-literal-to-reg:initialize-literal-type:
15083     # var type/edx: (payload tree type-id) = literal
15084     68/push 0/imm32/right:null
15085     68/push 0/imm32/right:null
15086     68/push 0/imm32/left:unused
15087     68/push 0/imm32/value:literal
15088     68/push 1/imm32/is-atom?:true
15089     68/push 0x11/imm32/alloc-id:fake:payload
15090     89/<- %edx 4/r32/esp
15091 $test-add-literal-to-reg:initialize-literal:
15092     # var l/edx: (payload var)
15093     68/push 0/imm32/register
15094     68/push 0/imm32/register
15095     68/push 0/imm32/no-stack-offset
15096     68/push 1/imm32/block-depth
15097     52/push-edx
15098     68/push 0x11/imm32/alloc-id:fake
15099     68/push 0/imm32/name
15100     68/push 0/imm32/name
15101     68/push 0x11/imm32/alloc-id:fake:payload
15102     89/<- %edx 4/r32/esp
15103 $test-add-literal-to-reg:initialize-literal-value:
15104     # l->name = "0x34"
15105     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15106     (copy-array Heap "0x34" %eax)
15107 $test-add-literal-to-reg:initialize-inouts:
15108     # var inouts/esi: (payload stmt-var) = [l]
15109     68/push 0/imm32/is-deref:false
15110     68/push 0/imm32/next
15111     68/push 0/imm32/next
15112     52/push-edx/l
15113     68/push 0x11/imm32/alloc-id:fake
15114     68/push 0x11/imm32/alloc-id:fake:payload
15115     89/<- %esi 4/r32/esp
15116 $test-add-literal-to-reg:initialize-outputs:
15117     # var outputs/edi: (payload stmt-var) = [v]
15118     68/push 0/imm32/is-deref:false
15119     68/push 0/imm32/next
15120     68/push 0/imm32/next
15121     51/push-ecx/v
15122     68/push 0x11/imm32/alloc-id:fake
15123     68/push 0x11/imm32/alloc-id:fake:payload
15124     89/<- %edi 4/r32/esp
15125 $test-add-literal-to-reg:initialize-stmt:
15126     # var stmt/esi: (addr statement)
15127     68/push 0/imm32/next
15128     68/push 0/imm32/next
15129     57/push-edi/outputs
15130     68/push 0x11/imm32/alloc-id:fake
15131     56/push-esi/inouts
15132     68/push 0x11/imm32/alloc-id:fake
15133     68/push 0/imm32/operation
15134     68/push 0/imm32/operation
15135     68/push 1/imm32/tag:stmt1
15136     89/<- %esi 4/r32/esp
15137 $test-add-literal-to-reg:initialize-stmt-operation:
15138     # stmt->operation = "add"
15139     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15140     (copy-array Heap "add" %eax)
15141     # convert
15142     c7 0/subop/copy *Curr-block-depth 0/imm32
15143     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15144     (flush _test-output-buffered-file)
15145 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15151     # check output
15152     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
15153     # . epilogue
15154     89/<- %esp 5/r32/ebp
15155     5d/pop-to-ebp
15156     c3/return
15157 
15158 test-add-literal-to-mem:
15159     #   add-to var1, 0x34
15160     # =>
15161     #   81 0/subop/add %eax 0x34/imm32
15162     #
15163     # . prologue
15164     55/push-ebp
15165     89/<- %ebp 4/r32/esp
15166     # setup
15167     (clear-stream _test-output-stream)
15168     (clear-stream $_test-output-buffered-file->buffer)
15169 $test-add-literal-to-mem:initialize-type:
15170     # var type/ecx: (payload tree type-id) = int
15171     68/push 0/imm32/right:null
15172     68/push 0/imm32/right:null
15173     68/push 0/imm32/left:unused
15174     68/push 1/imm32/value:int
15175     68/push 1/imm32/is-atom?:true
15176     68/push 0x11/imm32/alloc-id:fake:payload
15177     89/<- %ecx 4/r32/esp
15178 $test-add-literal-to-mem:initialize-var1:
15179     # var var1/ecx: (payload var)
15180     68/push 0/imm32/register
15181     68/push 0/imm32/register
15182     68/push 8/imm32/stack-offset
15183     68/push 1/imm32/block-depth
15184     51/push-ecx
15185     68/push 0x11/imm32/alloc-id:fake
15186     68/push 0/imm32/name
15187     68/push 0/imm32/name
15188     68/push 0x11/imm32/alloc-id:fake:payload
15189     89/<- %ecx 4/r32/esp
15190 $test-add-literal-to-mem:initialize-var1-name:
15191     # var1->name = "var1"
15192     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15193     (copy-array Heap "var1" %eax)
15194 $test-add-literal-to-mem:initialize-literal-type:
15195     # var type/edx: (payload tree type-id) = literal
15196     68/push 0/imm32/right:null
15197     68/push 0/imm32/right:null
15198     68/push 0/imm32/left:unused
15199     68/push 0/imm32/value:literal
15200     68/push 1/imm32/is-atom?:true
15201     68/push 0x11/imm32/alloc-id:fake:payload
15202     89/<- %edx 4/r32/esp
15203 $test-add-literal-to-mem:initialize-literal:
15204     # var l/edx: (payload var)
15205     68/push 0/imm32/register
15206     68/push 0/imm32/register
15207     68/push 0/imm32/no-stack-offset
15208     68/push 1/imm32/block-depth
15209     52/push-edx
15210     68/push 0x11/imm32/alloc-id:fake
15211     68/push 0/imm32/name
15212     68/push 0/imm32/name
15213     68/push 0x11/imm32/alloc-id:fake:payload
15214     89/<- %edx 4/r32/esp
15215 $test-add-literal-to-mem:initialize-literal-value:
15216     # l->name = "0x34"
15217     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15218     (copy-array Heap "0x34" %eax)
15219 $test-add-literal-to-mem:initialize-inouts:
15220     # var inouts/esi: (payload stmt-var) = [l]
15221     68/push 0/imm32/is-deref:false
15222     68/push 0/imm32/next
15223     68/push 0/imm32/next
15224     52/push-edx/l
15225     68/push 0x11/imm32/alloc-id:fake
15226     68/push 0x11/imm32/alloc-id:fake:payload
15227     89/<- %esi 4/r32/esp
15228     # var inouts = (handle stmt-var) = [var1, var2]
15229     68/push 0/imm32/is-deref:false
15230     56/push-esi/next
15231     68/push 0x11/imm32/alloc-id:fake
15232     51/push-ecx/var1
15233     68/push 0x11/imm32/alloc-id:fake
15234     68/push 0x11/imm32/alloc-id:fake:payload
15235     89/<- %esi 4/r32/esp
15236 $test-add-literal-to-mem:initialize-stmt:
15237     # var stmt/esi: (addr statement)
15238     68/push 0/imm32/next
15239     68/push 0/imm32/next
15240     68/push 0/imm32/outputs
15241     68/push 0/imm32/outputs
15242     56/push-esi/inouts
15243     68/push 0x11/imm32/alloc-id:fake
15244     68/push 0/imm32/operation
15245     68/push 0/imm32/operation
15246     68/push 1/imm32/tag:stmt1
15247     89/<- %esi 4/r32/esp
15248 $test-add-literal-to-mem:initialize-stmt-operation:
15249     # stmt->operation = "add-to"
15250     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15251     (copy-array Heap "add-to" %eax)
15252     # convert
15253     c7 0/subop/copy *Curr-block-depth 0/imm32
15254     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15255     (flush _test-output-buffered-file)
15256 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15262     # check output
15263     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
15264     # . epilogue
15265     89/<- %esp 5/r32/ebp
15266     5d/pop-to-ebp
15267     c3/return
15268 
15269 test-compare-mem-with-reg:
15270     #   compare var1, var2/eax
15271     # =>
15272     #   39/compare *(ebp+___) 0/r32/eax
15273     #
15274     # . prologue
15275     55/push-ebp
15276     89/<- %ebp 4/r32/esp
15277     # setup
15278     (clear-stream _test-output-stream)
15279     (clear-stream $_test-output-buffered-file->buffer)
15280 $test-compare-mem-with-reg:initialize-type:
15281     # var type/ecx: (payload tree type-id) = int
15282     68/push 0/imm32/right:null
15283     68/push 0/imm32/right:null
15284     68/push 0/imm32/left:unused
15285     68/push 1/imm32/value:int
15286     68/push 1/imm32/is-atom?:true
15287     68/push 0x11/imm32/alloc-id:fake:payload
15288     89/<- %ecx 4/r32/esp
15289 $test-compare-mem-with-reg:initialize-var1:
15290     # var var1/ecx: (payload var)
15291     68/push 0/imm32/register
15292     68/push 0/imm32/register
15293     68/push 8/imm32/stack-offset
15294     68/push 1/imm32/block-depth
15295     51/push-ecx
15296     68/push 0x11/imm32/alloc-id:fake
15297     68/push 0/imm32/name
15298     68/push 0/imm32/name
15299     68/push 0x11/imm32/alloc-id:fake:payload
15300     89/<- %ecx 4/r32/esp
15301 $test-compare-mem-with-reg:initialize-var1-name:
15302     # var1->name = "var1"
15303     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15304     (copy-array Heap "var1" %eax)
15305 $test-compare-mem-with-reg:initialize-var2:
15306     # var var2/edx: (payload var)
15307     68/push 0/imm32/register
15308     68/push 0/imm32/register
15309     68/push 0/imm32/no-stack-offset
15310     68/push 1/imm32/block-depth
15311     ff 6/subop/push *(ecx+0x10)
15312     68/push 0x11/imm32/alloc-id:fake
15313     68/push 0/imm32/name
15314     68/push 0/imm32/name
15315     68/push 0x11/imm32/alloc-id:fake:payload
15316     89/<- %edx 4/r32/esp
15317 $test-compare-mem-with-reg:initialize-var2-name:
15318     # var2->name = "var2"
15319     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15320     (copy-array Heap "var2" %eax)
15321 $test-compare-mem-with-reg:initialize-var2-register:
15322     # var2->register = "eax"
15323     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
15324     (copy-array Heap "eax" %eax)
15325 $test-compare-mem-with-reg:initialize-inouts:
15326     # var inouts/esi: (payload stmt-var) = [var2]
15327     68/push 0/imm32/is-deref:false
15328     68/push 0/imm32/next
15329     68/push 0/imm32/next
15330     52/push-edx/var2
15331     68/push 0x11/imm32/alloc-id:fake
15332     68/push 0x11/imm32/alloc-id:fake:payload
15333     89/<- %esi 4/r32/esp
15334     # inouts = [var1, var2]
15335     68/push 0/imm32/is-deref:false
15336     56/push-esi/next
15337     68/push 0x11/imm32/alloc-id:fake
15338     51/push-ecx/var1
15339     68/push 0x11/imm32/alloc-id:fake
15340     68/push 0x11/imm32/alloc-id:fake:payload
15341     89/<- %esi 4/r32/esp
15342 $test-compare-mem-with-reg:initialize-stmt:
15343     # var stmt/esi: (addr statement)
15344     68/push 0/imm32/next
15345     68/push 0/imm32/next
15346     68/push 0/imm32/outputs
15347     68/push 0/imm32/outputs
15348     56/push-esi/inouts
15349     68/push 0x11/imm32/alloc-id:fake
15350     68/push 0/imm32/operation
15351     68/push 0/imm32/operation
15352     68/push 1/imm32/tag:stmt1
15353     89/<- %esi 4/r32/esp
15354 $test-compare-mem-with-reg:initialize-stmt-operation:
15355     # stmt->operation = "compare"
15356     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15357     (copy-array Heap "compare" %eax)
15358     # convert
15359     c7 0/subop/copy *Curr-block-depth 0/imm32
15360     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15361     (flush _test-output-buffered-file)
15362 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15368     # check output
15369     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
15370     # . epilogue
15371     89/<- %esp 5/r32/ebp
15372     5d/pop-to-ebp
15373     c3/return
15374 
15375 test-compare-reg-with-mem:
15376     #   compare var1/eax, var2
15377     # =>
15378     #   3b/compare<- *(ebp+___) 0/r32/eax
15379     #
15380     # . prologue
15381     55/push-ebp
15382     89/<- %ebp 4/r32/esp
15383     # setup
15384     (clear-stream _test-output-stream)
15385     (clear-stream $_test-output-buffered-file->buffer)
15386 $test-compare-reg-with-mem:initialize-type:
15387     # var type/ecx: (payload tree type-id) = int
15388     68/push 0/imm32/right:null
15389     68/push 0/imm32/right:null
15390     68/push 0/imm32/left:unused
15391     68/push 1/imm32/value:int
15392     68/push 1/imm32/is-atom?:true
15393     68/push 0x11/imm32/alloc-id:fake:payload
15394     89/<- %ecx 4/r32/esp
15395 $test-compare-reg-with-mem:initialize-var1:
15396     # var var1/ecx: (payload var)
15397     68/push 0/imm32/register
15398     68/push 0/imm32/register
15399     68/push 0/imm32/no-stack-offset
15400     68/push 1/imm32/block-depth
15401     51/push-ecx
15402     68/push 0x11/imm32/alloc-id:fake
15403     68/push 0/imm32/name
15404     68/push 0/imm32/name
15405     68/push 0x11/imm32/alloc-id:fake:payload
15406     89/<- %ecx 4/r32/esp
15407 $test-compare-reg-with-mem:initialize-var1-name:
15408     # var1->name = "var1"
15409     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15410     (copy-array Heap "var1" %eax)
15411 $test-compare-reg-with-mem:initialize-var1-register:
15412     # var1->register = "eax"
15413     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15414     (copy-array Heap "eax" %eax)
15415 $test-compare-reg-with-mem:initialize-var2:
15416     # var var2/edx: (payload var)
15417     68/push 0/imm32/register
15418     68/push 0/imm32/register
15419     68/push 8/imm32/stack-offset
15420     68/push 1/imm32/block-depth
15421     ff 6/subop/push *(ecx+0x10)
15422     68/push 0x11/imm32/alloc-id:fake
15423     68/push 0/imm32/name
15424     68/push 0/imm32/name
15425     68/push 0x11/imm32/alloc-id:fake:payload
15426     89/<- %edx 4/r32/esp
15427 $test-compare-reg-with-mem:initialize-var2-name:
15428     # var2->name = "var2"
15429     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15430     (copy-array Heap "var2" %eax)
15431 $test-compare-reg-with-mem:initialize-inouts:
15432     # var inouts/esi: (payload stmt-var) = [var2]
15433     68/push 0/imm32/is-deref:false
15434     68/push 0/imm32/next
15435     68/push 0/imm32/next
15436     52/push-edx/var2
15437     68/push 0x11/imm32/alloc-id:fake
15438     68/push 0x11/imm32/alloc-id:fake:payload
15439     89/<- %esi 4/r32/esp
15440     # inouts = [var1, var2]
15441     68/push 0/imm32/is-deref:false
15442     56/push-esi/next
15443     68/push 0x11/imm32/alloc-id:fake
15444     51/push-ecx/var1
15445     68/push 0x11/imm32/alloc-id:fake
15446     68/push 0x11/imm32/alloc-id:fake:payload
15447     89/<- %esi 4/r32/esp
15448 $test-compare-reg-with-mem:initialize-stmt:
15449     # var stmt/esi: (addr statement)
15450     68/push 0/imm32/next
15451     68/push 0/imm32/next
15452     68/push 0/imm32/outputs
15453     68/push 0/imm32/outputs
15454     56/push-esi/inouts
15455     68/push 0x11/imm32/alloc-id:fake
15456     68/push 0/imm32/operation
15457     68/push 0/imm32/operation
15458     68/push 1/imm32/tag:stmt1
15459     89/<- %esi 4/r32/esp
15460 $test-compare-reg-with-mem:initialize-stmt-operation:
15461     # stmt->operation = "compare"
15462     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15463     (copy-array Heap "compare" %eax)
15464     # convert
15465     c7 0/subop/copy *Curr-block-depth 0/imm32
15466     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15467     (flush _test-output-buffered-file)
15468 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15474     # check output
15475     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
15476     # . epilogue
15477     89/<- %esp 5/r32/ebp
15478     5d/pop-to-ebp
15479     c3/return
15480 
15481 test-compare-mem-with-literal:
15482     #   compare var1, 0x34
15483     # =>
15484     #   81 7/subop/compare *(ebp+___) 0x34/imm32
15485     #
15486     # . prologue
15487     55/push-ebp
15488     89/<- %ebp 4/r32/esp
15489     # setup
15490     (clear-stream _test-output-stream)
15491     (clear-stream $_test-output-buffered-file->buffer)
15492 $test-compare-mem-with-literal:initialize-type:
15493     # var type/ecx: (payload tree type-id) = int
15494     68/push 0/imm32/right:null
15495     68/push 0/imm32/right:null
15496     68/push 0/imm32/left:unused
15497     68/push 1/imm32/value:int
15498     68/push 1/imm32/is-atom?:true
15499     68/push 0x11/imm32/alloc-id:fake:payload
15500     89/<- %ecx 4/r32/esp
15501 $test-compare-mem-with-literal:initialize-var1:
15502     # var var1/ecx: (payload var)
15503     68/push 0/imm32/register
15504     68/push 0/imm32/register
15505     68/push 8/imm32/stack-offset
15506     68/push 1/imm32/block-depth
15507     51/push-ecx
15508     68/push 0x11/imm32/alloc-id:fake
15509     68/push 0/imm32/name
15510     68/push 0/imm32/name
15511     68/push 0x11/imm32/alloc-id:fake:payload
15512     89/<- %ecx 4/r32/esp
15513 $test-compare-mem-with-literal:initialize-var1-name:
15514     # var1->name = "var1"
15515     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15516     (copy-array Heap "var1" %eax)
15517 $test-compare-mem-with-literal:initialize-literal-type:
15518     # var type/edx: (payload tree type-id) = literal
15519     68/push 0/imm32/right:null
15520     68/push 0/imm32/right:null
15521     68/push 0/imm32/left:unused
15522     68/push 0/imm32/value:literal
15523     68/push 1/imm32/is-atom?:true
15524     68/push 0x11/imm32/alloc-id:fake:payload
15525     89/<- %edx 4/r32/esp
15526 $test-compare-mem-with-literal:initialize-literal:
15527     # var l/edx: (payload var)
15528     68/push 0/imm32/register
15529     68/push 0/imm32/register
15530     68/push 0/imm32/no-stack-offset
15531     68/push 1/imm32/block-depth
15532     52/push-edx
15533     68/push 0x11/imm32/alloc-id:fake
15534     68/push 0/imm32/name
15535     68/push 0/imm32/name
15536     68/push 0x11/imm32/alloc-id:fake:payload
15537     89/<- %edx 4/r32/esp
15538 $test-compare-mem-with-literal:initialize-literal-value:
15539     # l->name = "0x34"
15540     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15541     (copy-array Heap "0x34" %eax)
15542 $test-compare-mem-with-literal:initialize-inouts:
15543     # var inouts/esi: (payload stmt-var) = [l]
15544     68/push 0/imm32/is-deref:false
15545     68/push 0/imm32/next
15546     68/push 0/imm32/next
15547     52/push-edx/l
15548     68/push 0x11/imm32/alloc-id:fake
15549     68/push 0x11/imm32/alloc-id:fake:payload
15550     89/<- %esi 4/r32/esp
15551     # var inouts = (handle stmt-var) = [var1, var2]
15552     68/push 0/imm32/is-deref:false
15553     56/push-esi/next
15554     68/push 0x11/imm32/alloc-id:fake
15555     51/push-ecx/var1
15556     68/push 0x11/imm32/alloc-id:fake
15557     68/push 0x11/imm32/alloc-id:fake:payload
15558     89/<- %esi 4/r32/esp
15559 $test-compare-mem-with-literal:initialize-stmt:
15560     # var stmt/esi: (addr statement)
15561     68/push 0/imm32/next
15562     68/push 0/imm32/next
15563     68/push 0/imm32/outputs
15564     68/push 0/imm32/outputs
15565     56/push-esi/inouts
15566     68/push 0x11/imm32/alloc-id:fake
15567     68/push 0/imm32/operation
15568     68/push 0/imm32/operation
15569     68/push 1/imm32/tag:stmt1
15570     89/<- %esi 4/r32/esp
15571 $test-compare-mem-with-literal:initialize-stmt-operation:
15572     # stmt->operation = "compare"
15573     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15574     (copy-array Heap "compare" %eax)
15575     # convert
15576     c7 0/subop/copy *Curr-block-depth 0/imm32
15577     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15578     (flush _test-output-buffered-file)
15579 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15585     # check output
15586     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
15587     # . epilogue
15588     89/<- %esp 5/r32/ebp
15589     5d/pop-to-ebp
15590     c3/return
15591 
15592 test-compare-eax-with-literal:
15593     #   compare var1/eax 0x34
15594     # =>
15595     #   3d/compare-eax-with 0x34/imm32
15596     #
15597     # . prologue
15598     55/push-ebp
15599     89/<- %ebp 4/r32/esp
15600     # setup
15601     (clear-stream _test-output-stream)
15602     (clear-stream $_test-output-buffered-file->buffer)
15603 $test-compare-eax-with-literal:initialize-type:
15604     # var type/ecx: (payload tree type-id) = int
15605     68/push 0/imm32/right:null
15606     68/push 0/imm32/right:null
15607     68/push 0/imm32/left:unused
15608     68/push 1/imm32/value:int
15609     68/push 1/imm32/is-atom?:true
15610     68/push 0x11/imm32/alloc-id:fake:payload
15611     89/<- %ecx 4/r32/esp
15612 $test-compare-eax-with-literal:initialize-var1:
15613     # var var1/ecx: (payload var)
15614     68/push 0/imm32/register
15615     68/push 0/imm32/register
15616     68/push 0/imm32/no-stack-offset
15617     68/push 1/imm32/block-depth
15618     51/push-ecx
15619     68/push 0x11/imm32/alloc-id:fake
15620     68/push 0/imm32/name
15621     68/push 0/imm32/name
15622     68/push 0x11/imm32/alloc-id:fake:payload
15623     89/<- %ecx 4/r32/esp
15624 $test-compare-eax-with-literal:initialize-var1-name:
15625     # var1->name = "var1"
15626     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15627     (copy-array Heap "var1" %eax)
15628 $test-compare-eax-with-literal:initialize-var1-register:
15629     # v->register = "eax"
15630     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15631     (copy-array Heap "eax" %eax)
15632 $test-compare-eax-with-literal:initialize-literal-type:
15633     # var type/edx: (payload tree type-id) = literal
15634     68/push 0/imm32/right:null
15635     68/push 0/imm32/right:null
15636     68/push 0/imm32/left:unused
15637     68/push 0/imm32/value:literal
15638     68/push 1/imm32/is-atom?:true
15639     68/push 0x11/imm32/alloc-id:fake:payload
15640     89/<- %edx 4/r32/esp
15641 $test-compare-eax-with-literal:initialize-literal:
15642     # var l/edx: (payload var)
15643     68/push 0/imm32/register
15644     68/push 0/imm32/register
15645     68/push 0/imm32/no-stack-offset
15646     68/push 1/imm32/block-depth
15647     52/push-edx
15648     68/push 0x11/imm32/alloc-id:fake
15649     68/push 0/imm32/name
15650     68/push 0/imm32/name
15651     68/push 0x11/imm32/alloc-id:fake:payload
15652     89/<- %edx 4/r32/esp
15653 $test-compare-eax-with-literal:initialize-literal-value:
15654     # l->name = "0x34"
15655     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15656     (copy-array Heap "0x34" %eax)
15657 $test-compare-eax-with-literal:initialize-inouts:
15658     # var inouts/esi: (payload stmt-var) = [l]
15659     68/push 0/imm32/is-deref:false
15660     68/push 0/imm32/next
15661     68/push 0/imm32/next
15662     52/push-edx/l
15663     68/push 0x11/imm32/alloc-id:fake
15664     68/push 0x11/imm32/alloc-id:fake:payload
15665     89/<- %esi 4/r32/esp
15666     # var inouts = (handle stmt-var) = [var1, var2]
15667     68/push 0/imm32/is-deref:false
15668     56/push-esi/next
15669     68/push 0x11/imm32/alloc-id:fake
15670     51/push-ecx/var1
15671     68/push 0x11/imm32/alloc-id:fake
15672     68/push 0x11/imm32/alloc-id:fake:payload
15673     89/<- %esi 4/r32/esp
15674 $test-compare-eax-with-literal:initialize-stmt:
15675     # var stmt/esi: (addr statement)
15676     68/push 0/imm32/next
15677     68/push 0/imm32/next
15678     68/push 0/imm32/outputs
15679     68/push 0/imm32/outputs
15680     56/push-esi/inouts
15681     68/push 0x11/imm32/alloc-id:fake
15682     68/push 0/imm32/operation
15683     68/push 0/imm32/operation
15684     68/push 1/imm32/tag:stmt1
15685     89/<- %esi 4/r32/esp
15686 $test-compare-eax-with-literal:initialize-stmt-operation:
15687     # stmt->operation = "compare"
15688     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15689     (copy-array Heap "compare" %eax)
15690     # convert
15691     c7 0/subop/copy *Curr-block-depth 0/imm32
15692     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15693     (flush _test-output-buffered-file)
15694 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15700     # check output
15701     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
15702     # . epilogue
15703     89/<- %esp 5/r32/ebp
15704     5d/pop-to-ebp
15705     c3/return
15706 
15707 test-compare-reg-with-literal:
15708     #   compare var1/ecx 0x34
15709     # =>
15710     #   81 7/subop/compare %ecx 0x34/imm32
15711     #
15712     # . prologue
15713     55/push-ebp
15714     89/<- %ebp 4/r32/esp
15715     # setup
15716     (clear-stream _test-output-stream)
15717     (clear-stream $_test-output-buffered-file->buffer)
15718 $test-compare-reg-with-literal:initialize-type:
15719     # var type/ecx: (payload tree type-id) = int
15720     68/push 0/imm32/right:null
15721     68/push 0/imm32/right:null
15722     68/push 0/imm32/left:unused
15723     68/push 1/imm32/value:int
15724     68/push 1/imm32/is-atom?:true
15725     68/push 0x11/imm32/alloc-id:fake:payload
15726     89/<- %ecx 4/r32/esp
15727 $test-compare-reg-with-literal:initialize-var1:
15728     # var var1/ecx: (payload var)
15729     68/push 0/imm32/register
15730     68/push 0/imm32/register
15731     68/push 0/imm32/no-stack-offset
15732     68/push 1/imm32/block-depth
15733     51/push-ecx
15734     68/push 0x11/imm32/alloc-id:fake
15735     68/push 0/imm32/name
15736     68/push 0/imm32/name
15737     68/push 0x11/imm32/alloc-id:fake:payload
15738     89/<- %ecx 4/r32/esp
15739 $test-compare-reg-with-literal:initialize-var1-name:
15740     # var1->name = "var1"
15741     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15742     (copy-array Heap "var1" %eax)
15743 $test-compare-reg-with-literal:initialize-var1-register:
15744     # v->register = "ecx"
15745     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15746     (copy-array Heap "ecx" %eax)
15747 $test-compare-reg-with-literal:initialize-literal-type:
15748     # var type/edx: (payload tree type-id) = literal
15749     68/push 0/imm32/right:null
15750     68/push 0/imm32/right:null
15751     68/push 0/imm32/left:unused
15752     68/push 0/imm32/value:literal
15753     68/push 1/imm32/is-atom?:true
15754     68/push 0x11/imm32/alloc-id:fake:payload
15755     89/<- %edx 4/r32/esp
15756 $test-compare-reg-with-literal:initialize-literal:
15757     # var l/edx: (payload var)
15758     68/push 0/imm32/register
15759     68/push 0/imm32/register
15760     68/push 0/imm32/no-stack-offset
15761     68/push 1/imm32/block-depth
15762     52/push-edx
15763     68/push 0x11/imm32/alloc-id:fake
15764     68/push 0/imm32/name
15765     68/push 0/imm32/name
15766     68/push 0x11/imm32/alloc-id:fake:payload
15767     89/<- %edx 4/r32/esp
15768 $test-compare-reg-with-literal:initialize-literal-value:
15769     # l->name = "0x34"
15770     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15771     (copy-array Heap "0x34" %eax)
15772 $test-compare-reg-with-literal:initialize-inouts:
15773     # var inouts/esi: (payload stmt-var) = [l]
15774     68/push 0/imm32/is-deref:false
15775     68/push 0/imm32/next
15776     68/push 0/imm32/next
15777     52/push-edx/l
15778     68/push 0x11/imm32/alloc-id:fake
15779     68/push 0x11/imm32/alloc-id:fake:payload
15780     89/<- %esi 4/r32/esp
15781     # var inouts = (handle stmt-var) = [var1, var2]
15782     68/push 0/imm32/is-deref:false
15783     56/push-esi/next
15784     68/push 0x11/imm32/alloc-id:fake
15785     51/push-ecx/var1
15786     68/push 0x11/imm32/alloc-id:fake
15787     68/push 0x11/imm32/alloc-id:fake:payload
15788     89/<- %esi 4/r32/esp
15789 $test-compare-reg-with-literal:initialize-stmt:
15790     # var stmt/esi: (addr statement)
15791     68/push 0/imm32/next
15792     68/push 0/imm32/next
15793     68/push 0/imm32/outputs
15794     68/push 0/imm32/outputs
15795     56/push-esi/inouts
15796     68/push 0x11/imm32/alloc-id:fake
15797     68/push 0/imm32/operation
15798     68/push 0/imm32/operation
15799     68/push 1/imm32/tag:stmt1
15800     89/<- %esi 4/r32/esp
15801 $test-compare-reg-with-literal:initialize-stmt-operation:
15802     # stmt->operation = "compare"
15803     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15804     (copy-array Heap "compare" %eax)
15805     # convert
15806     c7 0/subop/copy *Curr-block-depth 0/imm32
15807     (emit-subx-stmt _test-output-buffered-file %esi Primitives)
15808     (flush _test-output-buffered-file)
15809 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15815     # check output
15816     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
15817     # . epilogue
15818     89/<- %esp 5/r32/ebp
15819     5d/pop-to-ebp
15820     c3/return
15821 
15822 test-emit-subx-stmt-function-call:
15823     # Call a function on a variable on the stack.
15824     #   f foo
15825     # =>
15826     #   (f *(ebp-8))
15827     # (Changing the function name supports overloading in general, but here it
15828     # just serves to help disambiguate things.)
15829     #
15830     # There's a variable on the var stack as follows:
15831     #   name: 'foo'
15832     #   type: int
15833     #   stack-offset: -8
15834     #
15835     # There's nothing in primitives.
15836     #
15837     # We don't perform any checking here on the type of 'f'.
15838     #
15839     # . prologue
15840     55/push-ebp
15841     89/<- %ebp 4/r32/esp
15842     # setup
15843     (clear-stream _test-output-stream)
15844     (clear-stream $_test-output-buffered-file->buffer)
15845 $test-emit-subx-function-call:initialize-type:
15846     # var type/ecx: (payload tree type-id) = int
15847     68/push 0/imm32/right:null
15848     68/push 0/imm32/right:null
15849     68/push 0/imm32/left:unused
15850     68/push 1/imm32/value:int
15851     68/push 1/imm32/is-atom?:true
15852     68/push 0x11/imm32/alloc-id:fake:payload
15853     89/<- %ecx 4/r32/esp
15854 $test-emit-subx-function-call:initialize-var:
15855     # var var-foo/ecx: (payload var) = var(type)
15856     68/push 0/imm32/no-register
15857     68/push 0/imm32/no-register
15858     68/push -8/imm32/stack-offset
15859     68/push 1/imm32/block-depth
15860     51/push-ecx/type
15861     68/push 0x11/imm32/alloc-id:fake
15862     68/push 0/imm32/name
15863     68/push 0/imm32/name
15864     68/push 0x11/imm32/alloc-id:fake:payload
15865     89/<- %ecx 4/r32/esp
15866 $test-emit-subx-function-call:initialize-var-name:
15867     # var-foo->name = "foo"
15868     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15869     (copy-array Heap "foo" %eax)
15870 $test-emit-subx-function-call:initialize-stmt-var:
15871     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
15872     68/push 0/imm32/is-deref:false
15873     68/push 0/imm32/next
15874     68/push 0/imm32/next
15875     51/push-ecx/var-foo
15876     68/push 0x11/imm32/alloc-id:fake
15877     68/push 0x11/imm32/alloc-id:fake:payload
15878     89/<- %ebx 4/r32/esp
15879 $test-emit-subx-function-call:initialize-stmt:
15880     # var stmt/esi: (addr statement)
15881     68/push 0/imm32/no-outputs
15882     68/push 0/imm32/no-outputs
15883     53/push-ebx/inouts
15884     68/push 0x11/imm32/alloc-id:fake
15885     68/push 0/imm32/operation
15886     68/push 0/imm32/operation
15887     68/push 1/imm32/tag
15888     89/<- %esi 4/r32/esp
15889 $test-emit-subx-function-call:initialize-stmt-operation:
15890     # stmt->operation = "f"
15891     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15892     (copy-array Heap "f" %eax)
15893     # convert
15894     c7 0/subop/copy *Curr-block-depth 0/imm32
15895     (emit-subx-stmt _test-output-buffered-file %esi 0)
15896     (flush _test-output-buffered-file)
15897 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15903     # check output
15904     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
15905     # . epilogue
15906     89/<- %esp 5/r32/ebp
15907     5d/pop-to-ebp
15908     c3/return
15909 
15910 test-emit-subx-stmt-function-call-with-literal-arg:
15911     # Call a function on a literal.
15912     #   f 0x34
15913     # =>
15914     #   (f2 0x34)
15915     #
15916     # . prologue
15917     55/push-ebp
15918     89/<- %ebp 4/r32/esp
15919     # setup
15920     (clear-stream _test-output-stream)
15921     (clear-stream $_test-output-buffered-file->buffer)
15922 $test-emit-subx-function-call-with-literal-arg:initialize-type:
15923     # var type/ecx: (payload tree type-id) = int
15924     68/push 0/imm32/right:null
15925     68/push 0/imm32/right:null
15926     68/push 0/imm32/left:unused
15927     68/push 0/imm32/value:literal
15928     68/push 1/imm32/is-atom?:true
15929     68/push 0x11/imm32/alloc-id:fake:payload
15930     89/<- %ecx 4/r32/esp
15931 $test-emit-subx-function-call-with-literal-arg:initialize-var:
15932     # var var-foo/ecx: (payload var) = var(lit)
15933     68/push 0/imm32/no-register
15934     68/push 0/imm32/no-register
15935     68/push 0/imm32/no-stack-offset
15936     68/push 1/imm32/block-depth
15937     51/push-ecx/type
15938     68/push 0x11/imm32/alloc-id:fake
15939     68/push 0/imm32/name
15940     68/push 0/imm32/name
15941     68/push 0x11/imm32/alloc-id:fake:payload
15942     89/<- %ecx 4/r32/esp
15943 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
15944     # var-foo->name = "0x34"
15945     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15946     (copy-array Heap "0x34" %eax)
15947 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
15948     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
15949     68/push 0/imm32/is-deref:false
15950     68/push 0/imm32/next
15951     68/push 0/imm32/next
15952     51/push-ecx/var-foo
15953     68/push 0x11/imm32/alloc-id:fake
15954     68/push 0x11/imm32/alloc-id:fake:payload
15955     89/<- %ebx 4/r32/esp
15956 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
15957     # var stmt/esi: (addr statement)
15958     68/push 0/imm32/no-outputs
15959     68/push 0/imm32/no-outputs
15960     53/push-ebx/inouts
15961     68/push 0x11/imm32/alloc-id:fake
15962     68/push 0/imm32/operation
15963     68/push 0/imm32/operation
15964     68/push 1/imm32/tag
15965     89/<- %esi 4/r32/esp
15966 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
15967     # stmt->operation = "f"
15968     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15969     (copy-array Heap "f" %eax)
15970     # convert
15971     c7 0/subop/copy *Curr-block-depth 0/imm32
15972     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx)
15973     (flush _test-output-buffered-file)
15974 +--  6 lines: #?     # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------------------------------
15980     # check output
15981     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
15982     # . epilogue
15983     89/<- %esp 5/r32/ebp
15984     5d/pop-to-ebp
15985     c3/return
15986 
15987 emit-indent:  # out: (addr buffered-file), n: int
15988     # . prologue
15989     55/push-ebp
15990     89/<- %ebp 4/r32/esp
15991     # . save registers
15992     50/push-eax
15993     # var i/eax: int = n
15994     8b/-> *(ebp+0xc) 0/r32/eax
15995     {
15996       # if (i <= 0) break
15997       3d/compare-eax-with 0/imm32
15998       7e/jump-if-<= break/disp8
15999       (write-buffered *(ebp+8) "  ")
16000       48/decrement-eax
16001       eb/jump loop/disp8
16002     }
16003 $emit-indent:end:
16004     # . restore registers
16005     58/pop-to-eax
16006     # . epilogue
16007     89/<- %esp 5/r32/ebp
16008     5d/pop-to-ebp
16009     c3/return
16010 
16011 emit-subx-prologue:  # out: (addr buffered-file)
16012     # . prologue
16013     55/push-ebp
16014     89/<- %ebp 4/r32/esp
16015     #
16016     (write-buffered *(ebp+8) "  # . prologue\n")
16017     (write-buffered *(ebp+8) "  55/push-ebp\n")
16018     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
16019 $emit-subx-prologue:end:
16020     # . epilogue
16021     89/<- %esp 5/r32/ebp
16022     5d/pop-to-ebp
16023     c3/return
16024 
16025 emit-subx-epilogue:  # out: (addr buffered-file)
16026     # . prologue
16027     55/push-ebp
16028     89/<- %ebp 4/r32/esp
16029     #
16030     (write-buffered *(ebp+8) "  # . epilogue\n")
16031     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
16032     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
16033     (write-buffered *(ebp+8) "  c3/return\n")
16034 $emit-subx-epilogue:end:
16035     # . epilogue
16036     89/<- %esp 5/r32/ebp
16037     5d/pop-to-ebp
16038     c3/return