https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 
    7 # == Goals
    8 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
    9 # a bad pointer. (Requires strong type safety.)
   10 # 2. Do as little as possible to achieve goal 1. The translator should be
   11 # implementable in machine code.
   12 #   - minimize impedance mismatch between source language and SubX target
   13 #     (e.g. programmer manages registers manually)
   14 #   - checks over syntax
   15 #     (e.g. programmer's register allocation is checked)
   16 #   - runtime checks to avoid complex static analysis
   17 #     (e.g. array indexing always checks bounds)
   18 
   19 # == Language description
   20 # A program is a sequence of function and type definitions.
   21 #
   22 # Function example:
   23 #   fn foo n: int -> result/eax: int {
   24 #     ...
   25 #   }
   26 #
   27 # Functions consist of a name, optional inputs, optional outputs and a block.
   28 #
   29 # Function inputs and outputs are variables. All variables have a type and
   30 # storage specifier. They can be placed either in memory (on the stack) or in
   31 # one of 6 named registers.
   32 #   eax ecx edx ebx esi edi
   33 # Variables in registers must be primitive 32-bit types.
   34 # Variables not explicitly placed in a register are on the stack.
   35 #
   36 # Function inputs are always passed in memory (on the stack), while outputs
   37 # are always returned in registers.
   38 #
   39 # Blocks mostly consist of statements.
   40 #
   41 # Statements mostly consist of a name, optional inputs and optional outputs.
   42 #
   43 # Statement inputs are variables or literals. Variables need to specify type
   44 # (and storage) the first time they're mentioned but not later.
   45 #
   46 # Statement outputs, like function outputs, must be variables in registers.
   47 #
   48 # Statement names must be either primitives or user-defined functions.
   49 #
   50 # Primitives can write to any register.
   51 # User-defined functions only write to hard-coded registers. Outputs of each
   52 # call must have the same registers as in the function definition.
   53 #
   54 # There are some other statement types:
   55 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   56 #     prefixed with a label name and ':'
   57 #       - {
   58 #           ...
   59 #         }
   60 #       - foo: {
   61 #           ...
   62 #         }
   63 #
   64 #   - variable definitions on the stack. E.g.:
   65 #       - var foo: int
   66 #       - var bar: (array int 3)
   67 #     There's no initializer; variables are automatically initialized.
   68 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   69 #
   70 #   - variables definitions in a register. E.g.:
   71 #       - var foo/eax: int <- add bar 1
   72 #     The initializer is mandatory and must be a valid instruction that writes
   73 #     a single output to the right register. In practice registers will
   74 #     usually be either initialized by primitives or copied from eax.
   75 #       - var eax: int <- foo bar quux
   76 #         var floo/ecx: int <- copy eax
   77 #
   78 # Still todo:
   79 #   global variables
   80 #   heap allocations (planned name: 'handle')
   81 #   user-defined types: 'type' for structs, 'choice' for unions
   82 #   short-lived 'address' type for efficiently writing inside nested structs
   83 #
   84 # We don't have 'handle' types yet, but we try to distinguish 'ref', 'handle'
   85 # and 'address' in comments. Their definitions are in layer 50, but really you
   86 # can ignore the distinctions on a first reading of this program.
   87 #
   88 # Formal types:
   89 #   A program is a linked list of functions
   90 #   A function contains:
   91 #     name: (handle array byte)
   92 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   93 #       data: (handle var)
   94 #       next: (handle list)
   95 #     outputs: linked list of vars
   96 #       data: (handle var)
   97 #       next: (handle list)
   98 #     body: (handle block)
   99 #   A var-type contains:
  100 #     name: (handle array byte)
  101 #     type: (handle tree type-id)
  102 #
  103 #   A statement can be:
  104 #     tag 0: a block
  105 #     tag 1: a simple statement (stmt1)
  106 #     tag 2: a variable defined on the stack
  107 #     tag 3: a variable defined in a register
  108 #
  109 #   A block contains:
  110 #     tag: 0
  111 #     statements: (handle list stmt)
  112 #     name: (handle array byte) -- starting with '$'
  113 #
  114 #   A regular statement contains:
  115 #     tag: 1
  116 #     operation: (handle array byte)
  117 #     inouts: (handle list operand)
  118 #     outputs: (handle list var)
  119 #
  120 #   A variable defined on the stack contains:
  121 #     tag: 2
  122 #     name: (handle array byte)
  123 #     type: (handle tree type-id)
  124 #
  125 #   A variable defined in a register contains:
  126 #     tag: 3
  127 #     name: (handle array byte)
  128 #     type: (handle tree type-id)
  129 #     reg: (handle array byte)
  130 
  131 # == Translation: managing the stack
  132 # Now that we know what the language looks like in the large, let's think
  133 # about how translation happens from the bottom up. One crucial piece of the
  134 # puzzle is how Mu will clean up variables defined on the stack for you.
  135 #
  136 # Assume that we maintain a 'functions' list while parsing source code. And a
  137 # 'primitives' list is a global constant. Both these contain enough information
  138 # to perform type-checking on function calls or primitive statements, respectively.
  139 #
  140 # Defining variables pushes them on a stack with the current block depth and
  141 # enough information about their location (stack offset or register).
  142 # Starting a block increments the current block id.
  143 # Each statement now has enough information to emit code for it.
  144 # Ending a block is where the magic happens:
  145 #   pop all variables at the current block depth
  146 #   emit code to restore all register variables introduced at the current depth
  147 #   emit code to clean up all stack variables at the current depth (just increment esp)
  148 #   decrement the current block depth
  149 #
  150 # Formal types:
  151 #   live-vars: stack of vars
  152 #   var:
  153 #     name: (handle array byte)
  154 #     type: (handle tree type-id)
  155 #     block: int
  156 #     stack-offset: int  (added to ebp)
  157 #     register: (handle array byte)
  158 #       either usual register names
  159 #       or '*' to indicate any register
  160 #   At most one of stack-offset or register-index must be non-zero.
  161 #   A register of '*' designates a variable _template_. Only legal in formal
  162 #   parameters for primitives.
  163 
  164 # == Translating a single function call
  165 # This one's easy. Assuming we've already checked things, we just drop the
  166 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  167 #
  168 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  169 # =>
  170 # (subx-name inout1 inout2 inout3)
  171 #
  172 # Formal types:
  173 #   functions: linked list of info
  174 #     name: (handle array byte)
  175 #     inouts: linked list of vars
  176 #     outputs: linked list of vars
  177 #     body: block (singleton linked list)
  178 #     subx-name: (handle array byte)
  179 
  180 # == Translating a single primitive instruction
  181 # A second crucial piece of the puzzle is how Mu converts fairly regular
  182 # primitives with their uniform syntax to SubX instructions with their gnarly
  183 # x86 details.
  184 #
  185 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  186 # them.
  187 # SubX instructions have rm32 and r32 operands.
  188 # The translation between them covers almost all the possibilities.
  189 #   Instructions with 1 inout may turn into ones with 1 rm32
  190 #     (e.g. incrementing a var on the stack)
  191 #   Instructions with 1 output may turn into ones with 1 rm32
  192 #     (e.g. incrementing a var in a register)
  193 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  194 #     (e.g. adding a var to a reg)
  195 #   2 inouts may turn into 1 rm32 and 1 r32
  196 #     (e.g. adding a reg to a var)
  197 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  198 #     (e.g. adding a constant to a var)
  199 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  200 #     (e.g. adding a constant to a reg)
  201 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  202 #     (special-case: divide edx:eax by a var or reg)
  203 # Observations:
  204 #   We always emit rm32. It may be the first inout or the first output.
  205 #   We may emit r32 or imm32 or neither.
  206 #   When we emit r32 it may come from first inout or second inout or first output.
  207 #
  208 # Accordingly, the formal data structure for a primitive looks like this:
  209 #   primitives: linked list of info
  210 #     name: (handle array byte)
  211 #     mu-inouts: linked list of vars to check
  212 #     mu-outputs: linked list of vars to check; at most a singleton
  213 #     subx-name: (handle array byte)
  214 #     subx-rm32: enum arg-location
  215 #     subx-r32: enum arg-location
  216 #     subx-imm32: enum arg-location
  217 #     subx-disp32: enum arg-location
  218 #     output-is-write-only: boolean
  219 #   arg-location: enum
  220 #     0 means none
  221 #     1 means first inout
  222 #     2 means second inout
  223 #     3 means first output
  224 
  225 # == Translating a block
  226 # Emit block name if necessary
  227 # Emit '{'
  228 # When you encounter a statement, emit it as above
  229 # When you encounter a variable declaration
  230 #   emit any code needed for it (bzeros)
  231 #   push it on the var stack
  232 #   update register dict if necessary
  233 # When you encounter '}'
  234 #   While popping variables off the var stack until block id changes
  235 #     Emit code needed to clean up the stack
  236 #       either increment esp
  237 #       or pop into appropriate register
  238 
  239 # The rest is straightforward.
  240 
  241 == data
  242 
  243 Program:
  244 _Program-functions:  # (handle function)
  245   0/imm32
  246 _Program-functions->payload:
  247   0/imm32
  248 _Program-types:  # (handle typeinfo)
  249   0/imm32
  250 _Program-types->payload:
  251   0/imm32
  252 
  253 # Some constants for simulating the data structures described above.
  254 # Many constants here come with a type in a comment.
  255 #
  256 # Sometimes the type is of the value at that offset for the given type. For
  257 # example, if you start at a function record and move forward Function-inouts
  258 # bytes, you'll find a (handle list var).
  259 #
  260 # At other times, the type is of the constant itself. For example, the type of
  261 # the constant Function-size is (addr int). To get the size of a function,
  262 # look in *Function-size.
  263 
  264 Function-name:  # (handle array byte)
  265   0/imm32
  266 Function-inouts:  # (handle list var)
  267   8/imm32
  268 Function-outputs:  # (handle list var)
  269   0x10/imm32
  270 Function-body:  # (handle block)
  271   0x18/imm32
  272 Function-next:  # (handle function)
  273   0x20/imm32
  274 Function-size:  # (addr int)
  275   0x28/imm32/40
  276 
  277 Primitive-name:  # (handle array byte)
  278   0/imm32
  279 Primitive-inouts:  # (handle list var)
  280   8/imm32
  281 Primitive-outputs:  # (handle list var)
  282   0x10/imm32
  283 Primitive-subx-name:  # (handle array byte)
  284   0x18/imm32
  285 Primitive-subx-rm32:  # enum arg-location
  286   0x20/imm32
  287 Primitive-subx-r32:  # enum arg-location
  288   0x24/imm32
  289 Primitive-subx-imm32:  # enum arg-location
  290   0x28/imm32
  291 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  292   0x2c/imm32
  293 Primitive-output-is-write-only:  # boolean
  294   0x30/imm32
  295 Primitive-next:  # (handle function)
  296   0x34/imm32
  297 Primitive-size:  # (addr int)
  298   0x3c/imm32/60
  299 
  300 Stmt-tag:  # int
  301   0/imm32
  302 
  303 Block-stmts:  # (handle list stmt)
  304   4/imm32
  305 Block-var:  # (handle var)
  306   0xc/imm32
  307 
  308 Stmt1-operation:  # (handle array byte)
  309   4/imm32
  310 Stmt1-inouts:  # (handle stmt-var)
  311   0xc/imm32
  312 Stmt1-outputs:  # (handle stmt-var)
  313   0x14/imm32
  314 
  315 Vardef-var:  # (handle var)
  316   4/imm32
  317 
  318 Regvardef-operation:  # (handle array byte)
  319   4/imm32
  320 Regvardef-inouts:  # (handle stmt-var)
  321   0xc/imm32
  322 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  323   0x14/imm32
  324 
  325 Stmt-size:  # (addr int)
  326   0x1c/imm32
  327 
  328 Var-name:  # (handle array byte)
  329   0/imm32
  330 Var-type:  # (handle tree type-id)
  331   8/imm32
  332 Var-block-depth:  # int -- not available until code-generation time
  333   0x10/imm32
  334 Var-offset:  # int -- not available until code-generation time
  335   0x14/imm32
  336 Var-register:  # (handle array byte) -- name of a register
  337   0x18/imm32
  338 Var-size:  # (addr int)
  339   0x20/imm32
  340 
  341 List-value:  # (handle _)
  342   0/imm32
  343 List-next:  # (handle list _)
  344   8/imm32
  345 List-size:  # (addr int)
  346   0x10/imm32
  347 
  348 # A stmt-var is like a list of vars with call-site specific metadata
  349 Stmt-var-value:  # (handle var)
  350   0/imm32
  351 Stmt-var-next:  # (handle stmt-var)
  352   8/imm32
  353 Stmt-var-is-deref:  # boolean
  354   0x10/imm32
  355 Stmt-var-size:  # (addr int)
  356   0x14/imm32
  357 
  358 # A live-var is a var augmented with information needed for tracking live
  359 # variables.
  360 Live-var-value:  # (handle var)
  361   0/imm32
  362 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  363   8/imm32
  364 Live-var-size:  # (addr int)
  365   0xc/imm32
  366 
  367 # Types are expressed as trees (s-expressions) of type-ids (ints).
  368 
  369 Tree-is-atom:  # boolean
  370   0/imm32
  371 # if left-is-atom?
  372 Tree-value:  # type-id
  373   4/imm32
  374 # unless left-is-atom?
  375 Tree-left:  # (addr tree type-id)
  376   4/imm32
  377 Tree-right:  # (addr tree type-id)
  378   0xc/imm32
  379 #
  380 Tree-size:  # (addr int)
  381   0x14/imm32
  382 
  383 # Types
  384 
  385 # TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
  386 Type-id:  # (stream (addr array byte))
  387   0x20/imm32/write
  388   0/imm32/read
  389   0x100/imm32/size
  390   # data
  391   "literal"/imm32  # 0: value is just the name
  392   "int"/imm32  # 1
  393   "addr"/imm32  # 2
  394   "array"/imm32  # 3
  395   "handle"/imm32  # 4
  396   "boolean"/imm32  # 5
  397   "constant"/imm32  # 6: like a literal, but value is an int in Var-offset
  398   "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  399   # 0x20
  400   "byte"/imm32  # 8
  401           0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  402   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  403   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  404   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  405   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  406   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  407   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  408 
  409 # == Type definitions
  410 # Program->types contains some typeinfo for each type definition.
  411 # Types contain vars with types, but can't specify registers.
  412 Typeinfo-id:  # type-id
  413   0/imm32
  414 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  415   4/imm32
  416 # Total size must be >= 0
  417 # During parsing it may take on two additional values:
  418 #   -2: not yet initialized
  419 #   -1: in process of being computed
  420 # See populate-mu-type-sizes for details.
  421 Typeinfo-total-size-in-bytes:  # int
  422   0xc/imm32
  423 Typeinfo-next:  # (handle typeinfo)
  424   0x10/imm32
  425 Typeinfo-size:  # (addr int)
  426   0x18/imm32
  427 
  428 # Each entry in the typeinfo->fields table has a pointer to a string and a
  429 # pointer to a typeinfo-entry.
  430 Typeinfo-fields-row-size:  # (addr int)
  431   0x10/imm32
  432 
  433 # typeinfo-entry objects have information about a field in a single record type
  434 #
  435 # each field of a type is represented using two var's:
  436 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  437 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  438 # computing the output happens after parsing; in the meantime we preserve the
  439 # order of fields in the 'index' field.
  440 Typeinfo-entry-input-var:  # (handle var)
  441   0/imm32
  442 Typeinfo-entry-index:  # int
  443   8/imm32
  444 Typeinfo-entry-output-var:  # (handle var)
  445   0xc/imm32
  446 Typeinfo-entry-size:  # (addr int)
  447   0x14/imm32
  448 
  449 == code
  450 
  451 Entry:
  452     # . prologue
  453     89/<- %ebp 4/r32/esp
  454     (new-segment *Heap-size Heap)
  455     # if (argv[1] == "test') run-tests()
  456     {
  457       # if (argc <= 1) break
  458       81 7/subop/compare *ebp 1/imm32
  459       7e/jump-if-<= break/disp8
  460       # if (argv[1] != "test") break
  461       (kernel-string-equal? *(ebp+8) "test")  # => eax
  462       3d/compare-eax-and 0/imm32/false
  463       74/jump-if-= break/disp8
  464       #
  465       (run-tests)
  466       # syscall(exit, *Num-test-failures)
  467       8b/-> *Num-test-failures 3/r32/ebx
  468       eb/jump $mu-main:end/disp8
  469     }
  470     # otherwise convert Stdin
  471     (convert-mu Stdin Stdout Stderr 0)
  472     (flush Stdout)
  473     # syscall(exit, 0)
  474     bb/copy-to-ebx 0/imm32
  475 $mu-main:end:
  476     e8/call syscall_exit/disp32
  477 
  478 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  479     # . prologue
  480     55/push-ebp
  481     89/<- %ebp 4/r32/esp
  482     # initialize global data structures
  483     c7 0/subop/copy *Next-block-index 1/imm32
  484     c7 0/subop/copy *Type-id 0x24/imm32  # stream-write
  485     c7 0/subop/copy *_Program-functions 0/imm32
  486     c7 0/subop/copy *_Program-functions->payload 0/imm32
  487     c7 0/subop/copy *_Program-types 0/imm32
  488     c7 0/subop/copy *_Program-types->payload 0/imm32
  489     #
  490     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  491     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  492 #?     (dump-typeinfos "=== typeinfos\n")
  493     (check-mu-types)
  494     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  495 $convert-mu:end:
  496     # . epilogue
  497     89/<- %esp 5/r32/ebp
  498     5d/pop-to-ebp
  499     c3/return
  500 
  501 test-convert-empty-input:
  502     # empty input => empty output
  503     # . prologue
  504     55/push-ebp
  505     89/<- %ebp 4/r32/esp
  506     # setup
  507     (clear-stream _test-input-stream)
  508     (clear-stream $_test-input-buffered-file->buffer)
  509     (clear-stream _test-output-stream)
  510     (clear-stream $_test-output-buffered-file->buffer)
  511     #
  512     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  513     (flush _test-output-buffered-file)
  514     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  515     # . epilogue
  516     89/<- %esp 5/r32/ebp
  517     5d/pop-to-ebp
  518     c3/return
  519 
  520 test-convert-function-skeleton:
  521     # . prologue
  522     55/push-ebp
  523     89/<- %ebp 4/r32/esp
  524     # setup
  525     (clear-stream _test-input-stream)
  526     (clear-stream $_test-input-buffered-file->buffer)
  527     (clear-stream _test-output-stream)
  528     (clear-stream $_test-output-buffered-file->buffer)
  529     #
  530     (write _test-input-stream "fn foo {\n")
  531     (write _test-input-stream "}\n")
  532     # convert
  533     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  534     (flush _test-output-buffered-file)
  535 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  541     # check output
  542     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  543     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  544     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  545     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  546     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  547     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  548     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  549     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  550     # . epilogue
  551     89/<- %esp 5/r32/ebp
  552     5d/pop-to-ebp
  553     c3/return
  554 
  555 test-convert-multiple-function-skeletons:
  556     # . prologue
  557     55/push-ebp
  558     89/<- %ebp 4/r32/esp
  559     # setup
  560     (clear-stream _test-input-stream)
  561     (clear-stream $_test-input-buffered-file->buffer)
  562     (clear-stream _test-output-stream)
  563     (clear-stream $_test-output-buffered-file->buffer)
  564     #
  565     (write _test-input-stream "fn foo {\n")
  566     (write _test-input-stream "}\n")
  567     (write _test-input-stream "fn bar {\n")
  568     (write _test-input-stream "}\n")
  569     # convert
  570     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  571     (flush _test-output-buffered-file)
  572 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  578     # check first function
  579     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  580     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  581     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  582     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  583     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  584     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  585     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  586     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  587     # check second function
  588     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  589     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  590     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  591     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  592     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  593     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  594     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  595     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  596     # . epilogue
  597     89/<- %esp 5/r32/ebp
  598     5d/pop-to-ebp
  599     c3/return
  600 
  601 test-convert-function-with-arg:
  602     # . prologue
  603     55/push-ebp
  604     89/<- %ebp 4/r32/esp
  605     # setup
  606     (clear-stream _test-input-stream)
  607     (clear-stream $_test-input-buffered-file->buffer)
  608     (clear-stream _test-output-stream)
  609     (clear-stream $_test-output-buffered-file->buffer)
  610     #
  611     (write _test-input-stream "fn foo n: int {\n")
  612     (write _test-input-stream "}\n")
  613     # convert
  614     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  615     (flush _test-output-buffered-file)
  616 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  622     # check output
  623     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  624     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  625     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  626     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  627     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  628     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  629     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  630     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  631     # . epilogue
  632     89/<- %esp 5/r32/ebp
  633     5d/pop-to-ebp
  634     c3/return
  635 
  636 test-convert-function-with-arg-and-body:
  637     # . prologue
  638     55/push-ebp
  639     89/<- %ebp 4/r32/esp
  640     # setup
  641     (clear-stream _test-input-stream)
  642     (clear-stream $_test-input-buffered-file->buffer)
  643     (clear-stream _test-output-stream)
  644     (clear-stream $_test-output-buffered-file->buffer)
  645     #
  646     (write _test-input-stream "fn foo n: int {\n")
  647     (write _test-input-stream "  increment n\n")
  648     (write _test-input-stream "}\n")
  649     # convert
  650     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  651     (flush _test-output-buffered-file)
  652 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  658     # check output
  659     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  660     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  661     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  662     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  663     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  664     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  665     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  666     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  667     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  668     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  669     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  670     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  671     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  672     # . epilogue
  673     89/<- %esp 5/r32/ebp
  674     5d/pop-to-ebp
  675     c3/return
  676 
  677 test-convert-function-distinguishes-args:
  678     # . prologue
  679     55/push-ebp
  680     89/<- %ebp 4/r32/esp
  681     # setup
  682     (clear-stream _test-input-stream)
  683     (clear-stream $_test-input-buffered-file->buffer)
  684     (clear-stream _test-output-stream)
  685     (clear-stream $_test-output-buffered-file->buffer)
  686     #
  687     (write _test-input-stream "fn foo a: int, b: int {\n")
  688     (write _test-input-stream "  increment b\n")
  689     (write _test-input-stream "}\n")
  690     # convert
  691     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  692     (flush _test-output-buffered-file)
  693 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  699     # check output
  700     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  701     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  702     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  703     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  704     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  705     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  706     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  707     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  708     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  709     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  710     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  711     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  712     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  713     # . epilogue
  714     89/<- %esp 5/r32/ebp
  715     5d/pop-to-ebp
  716     c3/return
  717 
  718 test-convert-function-returns-result:
  719     # . prologue
  720     55/push-ebp
  721     89/<- %ebp 4/r32/esp
  722     # setup
  723     (clear-stream _test-input-stream)
  724     (clear-stream $_test-input-buffered-file->buffer)
  725     (clear-stream _test-output-stream)
  726     (clear-stream $_test-output-buffered-file->buffer)
  727     #
  728     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  729     (write _test-input-stream "  result <- copy a\n")
  730     (write _test-input-stream "  result <- increment\n")
  731     (write _test-input-stream "}\n")
  732     # convert
  733     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  734     (flush _test-output-buffered-file)
  735 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  741     # check output
  742     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  743     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  744     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  745     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  746     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  748     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  749     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  750     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  751     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  752     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  753     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  754     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  755     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  756     # . epilogue
  757     89/<- %esp 5/r32/ebp
  758     5d/pop-to-ebp
  759     c3/return
  760 
  761 test-convert-function-with-literal-arg:
  762     # . prologue
  763     55/push-ebp
  764     89/<- %ebp 4/r32/esp
  765     # setup
  766     (clear-stream _test-input-stream)
  767     (clear-stream $_test-input-buffered-file->buffer)
  768     (clear-stream _test-output-stream)
  769     (clear-stream $_test-output-buffered-file->buffer)
  770     #
  771     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  772     (write _test-input-stream "  result <- copy a\n")
  773     (write _test-input-stream "  result <- add 1\n")
  774     (write _test-input-stream "}\n")
  775     # convert
  776     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  777     (flush _test-output-buffered-file)
  778 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  784     # check output
  785     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  786     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  787     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  788     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  789     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  790     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  791     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  792     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  793     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  794     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  795     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  796     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  797     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  798     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  799     # . epilogue
  800     89/<- %esp 5/r32/ebp
  801     5d/pop-to-ebp
  802     c3/return
  803 
  804 test-convert-function-with-literal-arg-2:
  805     # . prologue
  806     55/push-ebp
  807     89/<- %ebp 4/r32/esp
  808     # setup
  809     (clear-stream _test-input-stream)
  810     (clear-stream $_test-input-buffered-file->buffer)
  811     (clear-stream _test-output-stream)
  812     (clear-stream $_test-output-buffered-file->buffer)
  813     #
  814     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  815     (write _test-input-stream "  result <- copy a\n")
  816     (write _test-input-stream "  result <- add 1\n")
  817     (write _test-input-stream "}\n")
  818     # convert
  819     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  820     (flush _test-output-buffered-file)
  821 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  827     # check output
  828     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  829     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  830     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  831     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  832     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  834     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  835     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  836     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  837     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  838     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  839     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  840     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  841     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  842     # . epilogue
  843     89/<- %esp 5/r32/ebp
  844     5d/pop-to-ebp
  845     c3/return
  846 
  847 test-convert-function-call-with-literal-arg:
  848     # . prologue
  849     55/push-ebp
  850     89/<- %ebp 4/r32/esp
  851     # setup
  852     (clear-stream _test-input-stream)
  853     (clear-stream $_test-input-buffered-file->buffer)
  854     (clear-stream _test-output-stream)
  855     (clear-stream $_test-output-buffered-file->buffer)
  856     #
  857     (write _test-input-stream "fn main -> result/ebx: int {\n")
  858     (write _test-input-stream "  result <- do-add 3 4\n")
  859     (write _test-input-stream "}\n")
  860     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  861     (write _test-input-stream "  result <- copy a\n")
  862     (write _test-input-stream "  result <- add b\n")
  863     (write _test-input-stream "}\n")
  864     # convert
  865     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  866     (flush _test-output-buffered-file)
  867 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  873     # check output
  874     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  875     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  876     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  877     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  878     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  879     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  880     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  881     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  882     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  883     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  884     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  885     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  886     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  887     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  888     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  889     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  890     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  891     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  892     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  893     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  894     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  895     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  896     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  897     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  898     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  899     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  900     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  901     # . epilogue
  902     89/<- %esp 5/r32/ebp
  903     5d/pop-to-ebp
  904     c3/return
  905 
  906 test-convert-function-with-local-var-in-mem:
  907     # . prologue
  908     55/push-ebp
  909     89/<- %ebp 4/r32/esp
  910     # setup
  911     (clear-stream _test-input-stream)
  912     (clear-stream $_test-input-buffered-file->buffer)
  913     (clear-stream _test-output-stream)
  914     (clear-stream $_test-output-buffered-file->buffer)
  915     #
  916     (write _test-input-stream "fn foo {\n")
  917     (write _test-input-stream "  var x: int\n")
  918     (write _test-input-stream "  increment x\n")
  919     (write _test-input-stream "}\n")
  920     # convert
  921     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  922     (flush _test-output-buffered-file)
  923 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  929     # check output
  930     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  931     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  932     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  933     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  934     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  935     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  936     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  937     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  938     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem/8")
  939     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  940     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  941     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  942     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  943     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  944     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  945     # . epilogue
  946     89/<- %esp 5/r32/ebp
  947     5d/pop-to-ebp
  948     c3/return
  949 
  950 test-local-var-in-mem-has-no-initializer:
  951     # . prologue
  952     55/push-ebp
  953     89/<- %ebp 4/r32/esp
  954     # setup
  955     (clear-stream _test-input-stream)
  956     (clear-stream $_test-input-buffered-file->buffer)
  957     (clear-stream _test-output-stream)
  958     (clear-stream $_test-output-buffered-file->buffer)
  959     (clear-stream _test-error-stream)
  960     (clear-stream $_test-error-buffered-file->buffer)
  961     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
  962     68/push 0/imm32
  963     68/push 0/imm32
  964     89/<- %edx 4/r32/esp
  965     (tailor-exit-descriptor %edx 0x10)
  966     #
  967     (write _test-input-stream "fn foo {\n")
  968     (write _test-input-stream "  var x: int <- copy 0\n")
  969     (write _test-input-stream "  increment x\n")
  970     (write _test-input-stream "}\n")
  971     # convert
  972     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
  973     # registers except esp clobbered at this point
  974     # restore ed
  975     89/<- %edx 4/r32/esp
  976     (flush _test-output-buffered-file)
  977     (flush _test-error-buffered-file)
  978 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
  984     # check output
  985     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
  986     (check-next-stream-line-equal _test-error-stream  "fn foo: var x: variables on the stack can't take an initializer"  "F - test-var-in-mem-has-no-initializer: error message")
  987     # check that stop(1) was called
  988     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
  989     # don't restore from ebp
  990     81 0/subop/add %esp 8/imm32
  991     # . epilogue
  992     5d/pop-to-ebp
  993     c3/return
  994 
  995 test-convert-function-with-local-var-with-compound-type-in-mem:
  996     # . prologue
  997     55/push-ebp
  998     89/<- %ebp 4/r32/esp
  999     # setup
 1000     (clear-stream _test-input-stream)
 1001     (clear-stream $_test-input-buffered-file->buffer)
 1002     (clear-stream _test-output-stream)
 1003     (clear-stream $_test-output-buffered-file->buffer)
 1004     #
 1005     (write _test-input-stream "fn foo {\n")
 1006     (write _test-input-stream "  var x: (addr int)\n")
 1007     (write _test-input-stream "  copy-to x, 0\n")
 1008     (write _test-input-stream "}\n")
 1009     # convert
 1010     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1011     (flush _test-output-buffered-file)
 1012 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1018     # check output
 1019     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1020     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1021     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1022     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/3")
 1023     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1024     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1025     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-compound-type-in-mem/6")
 1026     (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/7")
 1027     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/8")
 1028     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1029     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1030     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1031     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/12")
 1032     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-compound-type-in-mem/13")
 1033     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1034     # . epilogue
 1035     89/<- %esp 5/r32/ebp
 1036     5d/pop-to-ebp
 1037     c3/return
 1038 
 1039 test-convert-function-with-local-var-in-reg:
 1040     # . prologue
 1041     55/push-ebp
 1042     89/<- %ebp 4/r32/esp
 1043     # setup
 1044     (clear-stream _test-input-stream)
 1045     (clear-stream $_test-input-buffered-file->buffer)
 1046     (clear-stream _test-output-stream)
 1047     (clear-stream $_test-output-buffered-file->buffer)
 1048     #
 1049     (write _test-input-stream "fn foo {\n")
 1050     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1051     (write _test-input-stream "  x <- increment\n")
 1052     (write _test-input-stream "}\n")
 1053     # convert
 1054     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1055     (flush _test-output-buffered-file)
 1056 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1062     # check output
 1063     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1064     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1065     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1066     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1067     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1069     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1070     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1071     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1072     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1073     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1074     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1075     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1076     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1077     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1078     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1079     # . epilogue
 1080     89/<- %esp 5/r32/ebp
 1081     5d/pop-to-ebp
 1082     c3/return
 1083 
 1084 test-convert-function-with-second-local-var-in-same-reg:
 1085     # . prologue
 1086     55/push-ebp
 1087     89/<- %ebp 4/r32/esp
 1088     # setup
 1089     (clear-stream _test-input-stream)
 1090     (clear-stream $_test-input-buffered-file->buffer)
 1091     (clear-stream _test-output-stream)
 1092     (clear-stream $_test-output-buffered-file->buffer)
 1093     #
 1094     (write _test-input-stream "fn foo {\n")
 1095     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1096     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1097     (write _test-input-stream "  y <- increment\n")
 1098     (write _test-input-stream "}\n")
 1099     # convert
 1100     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1101     (flush _test-output-buffered-file)
 1102 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1108     # check output
 1109     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1110     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1111     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1112     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-second-local-var-in-same-reg/3")
 1113     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1114     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1115     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-second-local-var-in-same-reg/6")
 1116     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/7")
 1117     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/8")
 1118     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1119     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10")
 1120     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1121     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1122     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1123     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-second-local-var-in-same-reg/14")
 1124     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1125     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1126     # . epilogue
 1127     89/<- %esp 5/r32/ebp
 1128     5d/pop-to-ebp
 1129     c3/return
 1130 
 1131 test-convert-function-with-local-var-dereferenced:
 1132     # . prologue
 1133     55/push-ebp
 1134     89/<- %ebp 4/r32/esp
 1135     # setup
 1136     (clear-stream _test-input-stream)
 1137     (clear-stream $_test-input-buffered-file->buffer)
 1138     (clear-stream _test-output-stream)
 1139     (clear-stream $_test-output-buffered-file->buffer)
 1140     #
 1141     (write _test-input-stream "fn foo {\n")
 1142     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1143     (write _test-input-stream "  increment *x\n")
 1144     (write _test-input-stream "}\n")
 1145     # convert
 1146     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1147     (flush _test-output-buffered-file)
 1148 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1154     # check output
 1155     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1156     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1157     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1158     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1159     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1160     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1161     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1162     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1163     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1164     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1165     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1167     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1168     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1169     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1170     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1171     # . epilogue
 1172     89/<- %esp 5/r32/ebp
 1173     5d/pop-to-ebp
 1174     c3/return
 1175 
 1176 # variables of type 'byte' are not allowed on the stack
 1177 test-convert-function-with-byte-operations:
 1178     # . prologue
 1179     55/push-ebp
 1180     89/<- %ebp 4/r32/esp
 1181     # setup
 1182     (clear-stream _test-input-stream)
 1183     (clear-stream $_test-input-buffered-file->buffer)
 1184     (clear-stream _test-output-stream)
 1185     (clear-stream $_test-output-buffered-file->buffer)
 1186     #
 1187     (write _test-input-stream "fn foo {\n")
 1188     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 1189     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 1190     (write _test-input-stream "  y <- copy-byte x\n")
 1191     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 1192     (write _test-input-stream "  y <- copy-byte *z\n")
 1193     (write _test-input-stream "  copy-byte-to *z, x\n")
 1194     (write _test-input-stream "}\n")
 1195     # convert
 1196     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1197     (flush _test-output-buffered-file)
 1198 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1204     # check output
 1205     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 1206     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 1207     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 1208     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 1209     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 1210     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 1211     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 1212     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 1213     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 1214     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 1215     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 1216     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 1217     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 1218     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 1219     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 1220     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 1221     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 1222     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 1223     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 1224     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 1225     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 1226     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 1227     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 1228     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 1229     # . epilogue
 1230     89/<- %esp 5/r32/ebp
 1231     5d/pop-to-ebp
 1232     c3/return
 1233 
 1234 test-convert-compare-register-with-literal:
 1235     # . prologue
 1236     55/push-ebp
 1237     89/<- %ebp 4/r32/esp
 1238     # setup
 1239     (clear-stream _test-input-stream)
 1240     (clear-stream $_test-input-buffered-file->buffer)
 1241     (clear-stream _test-output-stream)
 1242     (clear-stream $_test-output-buffered-file->buffer)
 1243     #
 1244     (write _test-input-stream "fn foo {\n")
 1245     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1246     (write _test-input-stream "  compare x, 0\n")
 1247     (write _test-input-stream "}\n")
 1248     # convert
 1249     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1250     (flush _test-output-buffered-file)
 1251 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1257     # check output
 1258     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1259     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1260     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1261     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1262     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1263     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1264     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1265     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1266     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1267     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1268     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1269     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1270     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1271     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1272     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1273     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1274     # . epilogue
 1275     89/<- %esp 5/r32/ebp
 1276     5d/pop-to-ebp
 1277     c3/return
 1278 
 1279 test-convert-function-with-local-var-in-block:
 1280     # . prologue
 1281     55/push-ebp
 1282     89/<- %ebp 4/r32/esp
 1283     # setup
 1284     (clear-stream _test-input-stream)
 1285     (clear-stream $_test-input-buffered-file->buffer)
 1286     (clear-stream _test-output-stream)
 1287     (clear-stream $_test-output-buffered-file->buffer)
 1288     #
 1289     (write _test-input-stream "fn foo {\n")
 1290     (write _test-input-stream "  {\n")
 1291     (write _test-input-stream "    var x: int\n")
 1292     (write _test-input-stream "    increment x\n")
 1293     (write _test-input-stream "  }\n")
 1294     (write _test-input-stream "}\n")
 1295     # convert
 1296     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1297     (flush _test-output-buffered-file)
 1298 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1304     # check output
 1305     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1306     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1307     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1308     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1309     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1310     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1311     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1312     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1313     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1314     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1315     (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")
 1316     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1317     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1318     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1319     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1320     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1321     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1322     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1323     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1324     # . epilogue
 1325     89/<- %esp 5/r32/ebp
 1326     5d/pop-to-ebp
 1327     c3/return
 1328 
 1329 test-convert-function-with-local-var-in-named-block:
 1330     # . prologue
 1331     55/push-ebp
 1332     89/<- %ebp 4/r32/esp
 1333     # setup
 1334     (clear-stream _test-input-stream)
 1335     (clear-stream $_test-input-buffered-file->buffer)
 1336     (clear-stream _test-output-stream)
 1337     (clear-stream $_test-output-buffered-file->buffer)
 1338     #
 1339     (write _test-input-stream "fn foo {\n")
 1340     (write _test-input-stream "  $bar: {\n")
 1341     (write _test-input-stream "    var x: int\n")
 1342     (write _test-input-stream "    increment x\n")
 1343     (write _test-input-stream "  }\n")
 1344     (write _test-input-stream "}\n")
 1345     # convert
 1346     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1347     (flush _test-output-buffered-file)
 1348 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1354     # check output
 1355     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1356     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1357     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1358     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1359     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1360     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1361     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1362     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1363     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1364     (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")
 1365     (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")
 1366     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1367     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1368     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1369     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1370     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1371     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1372     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1373     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1374     # . epilogue
 1375     89/<- %esp 5/r32/ebp
 1376     5d/pop-to-ebp
 1377     c3/return
 1378 
 1379 test-always-shadow-outermost-reg-vars-in-function:
 1380     # . prologue
 1381     55/push-ebp
 1382     89/<- %ebp 4/r32/esp
 1383     # setup
 1384     (clear-stream _test-input-stream)
 1385     (clear-stream $_test-input-buffered-file->buffer)
 1386     (clear-stream _test-output-stream)
 1387     (clear-stream $_test-output-buffered-file->buffer)
 1388     #
 1389     (write _test-input-stream "fn foo {\n")
 1390     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1391     (write _test-input-stream "}\n")
 1392     # convert
 1393     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1394     (flush _test-output-buffered-file)
 1395 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1401     # check output
 1402     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 1403     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 1404     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 1405     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 1406     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 1407     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 1408     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1409     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 1410     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1411     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 1412     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 1413     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 1414     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 1415     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 1416     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 1417     # . epilogue
 1418     89/<- %esp 5/r32/ebp
 1419     5d/pop-to-ebp
 1420     c3/return
 1421 
 1422 _pending-test-clobber-dead-local:
 1423     # . prologue
 1424     55/push-ebp
 1425     89/<- %ebp 4/r32/esp
 1426     # setup
 1427     (clear-stream _test-input-stream)
 1428     (clear-stream $_test-input-buffered-file->buffer)
 1429     (clear-stream _test-output-stream)
 1430     (clear-stream $_test-output-buffered-file->buffer)
 1431     #
 1432     (write _test-input-stream "fn foo {\n")
 1433     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1434     (write _test-input-stream "  {\n")
 1435     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1436     (write _test-input-stream "  }\n")
 1437     (write _test-input-stream "}\n")
 1438     # convert
 1439     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1440     (flush _test-output-buffered-file)
 1441 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1447     # check output
 1448     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 1449     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 1450     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 1451     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 1452     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 1453     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 1454     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 1455     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 1456     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 1457     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 1458     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 1459     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 1460     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 1461     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 1462     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 1463     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 1464     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 1465     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 1466     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 1467     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 1468     # . epilogue
 1469     89/<- %esp 5/r32/ebp
 1470     5d/pop-to-ebp
 1471     c3/return
 1472 
 1473 test-shadow-live-local:
 1474     # . prologue
 1475     55/push-ebp
 1476     89/<- %ebp 4/r32/esp
 1477     # setup
 1478     (clear-stream _test-input-stream)
 1479     (clear-stream $_test-input-buffered-file->buffer)
 1480     (clear-stream _test-output-stream)
 1481     (clear-stream $_test-output-buffered-file->buffer)
 1482     #
 1483     (write _test-input-stream "fn foo {\n")
 1484     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1485     (write _test-input-stream "  {\n")
 1486     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1487     (write _test-input-stream "  }\n")
 1488     (write _test-input-stream "  x <- increment\n")
 1489     (write _test-input-stream "}\n")
 1490     # convert
 1491     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1492     (flush _test-output-buffered-file)
 1493 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1499     # check output
 1500     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 1501     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 1502     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 1503     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 1504     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 1505     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 1506     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 1507     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 1508     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 1509     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 1510     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 1511     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 1512     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 1513     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 1514     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 1515     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 1516     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 1517     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 1518     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 1519     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 1520     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 1521     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 1522     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/21")
 1523     # . epilogue
 1524     89/<- %esp 5/r32/ebp
 1525     5d/pop-to-ebp
 1526     c3/return
 1527 
 1528 test-do-not-spill-same-register-in-block:
 1529     # . prologue
 1530     55/push-ebp
 1531     89/<- %ebp 4/r32/esp
 1532     # setup
 1533     (clear-stream _test-input-stream)
 1534     (clear-stream $_test-input-buffered-file->buffer)
 1535     (clear-stream _test-output-stream)
 1536     (clear-stream $_test-output-buffered-file->buffer)
 1537     #
 1538     (write _test-input-stream "fn foo {\n")
 1539     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1540     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1541     (write _test-input-stream "  y <- increment\n")
 1542     (write _test-input-stream "}\n")
 1543     # convert
 1544     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1545     (flush _test-output-buffered-file)
 1546 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1552     # check output
 1553     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 1554     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 1555     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 1556     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 1557     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 1558     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 1559     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 1560     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 1561     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 1562     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 1563     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 1564     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 1565     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 1566     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 1567     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 1568     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 1569     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 1570     # . epilogue
 1571     89/<- %esp 5/r32/ebp
 1572     5d/pop-to-ebp
 1573     c3/return
 1574 
 1575 test-spill-different-register-in-block:
 1576     # . prologue
 1577     55/push-ebp
 1578     89/<- %ebp 4/r32/esp
 1579     # setup
 1580     (clear-stream _test-input-stream)
 1581     (clear-stream $_test-input-buffered-file->buffer)
 1582     (clear-stream _test-output-stream)
 1583     (clear-stream $_test-output-buffered-file->buffer)
 1584     #
 1585     (write _test-input-stream "fn foo {\n")
 1586     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 1587     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1588     (write _test-input-stream "  y <- increment\n")
 1589     (write _test-input-stream "}\n")
 1590     # convert
 1591     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1592     (flush _test-output-buffered-file)
 1593 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1599     # check output
 1600     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 1601     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 1602     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 1603     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 1604     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 1605     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 1606     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 1607     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 1608     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 1609     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 1610     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 1611     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 1612     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 1613     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 1614     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 1615     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 1616     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 1617     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 1618     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 1619     # . epilogue
 1620     89/<- %esp 5/r32/ebp
 1621     5d/pop-to-ebp
 1622     c3/return
 1623 
 1624 test-shadow-live-output:
 1625     # . prologue
 1626     55/push-ebp
 1627     89/<- %ebp 4/r32/esp
 1628     # setup
 1629     (clear-stream _test-input-stream)
 1630     (clear-stream $_test-input-buffered-file->buffer)
 1631     (clear-stream _test-output-stream)
 1632     (clear-stream $_test-output-buffered-file->buffer)
 1633     #
 1634     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1635     (write _test-input-stream "  x <- copy 3\n")
 1636     (write _test-input-stream "  {\n")
 1637     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 1638     (write _test-input-stream "  }\n")
 1639     (write _test-input-stream "  x <- increment\n")
 1640     (write _test-input-stream "}\n")
 1641     # convert
 1642     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1643     (flush _test-output-buffered-file)
 1644 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1650     # check output
 1651     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 1652     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 1653     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 1654     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 1655     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 1656     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 1657     (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
 1658     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 1659     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 1660     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 1661     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 1662     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 1663     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 1664     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 1665     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 1666     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 1667     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 1668     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 1669     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 1670     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 1671     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 1672     # . epilogue
 1673     89/<- %esp 5/r32/ebp
 1674     5d/pop-to-ebp
 1675     c3/return
 1676 
 1677 test-local-clobbered-by-output:
 1678     # also doesn't spill
 1679     # . prologue
 1680     55/push-ebp
 1681     89/<- %ebp 4/r32/esp
 1682     # setup
 1683     (clear-stream _test-input-stream)
 1684     (clear-stream $_test-input-buffered-file->buffer)
 1685     (clear-stream _test-output-stream)
 1686     (clear-stream $_test-output-buffered-file->buffer)
 1687     #
 1688     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1689     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1690     (write _test-input-stream "  x <- copy y\n")
 1691     (write _test-input-stream "}\n")
 1692     # convert
 1693     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1694     (flush _test-output-buffered-file)
 1695 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1701     # check output
 1702     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-output/0")
 1703     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-output/1")
 1704     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-output/2")
 1705     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-output/3")
 1706     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-output/4")
 1707     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-output/5")
 1708     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-output/6")
 1709     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-output/7")
 1710     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-output/8")
 1711     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-output/9")
 1712     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-output/10")
 1713     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-output/11")
 1714     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-output/12")
 1715     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-output/13")
 1716     # . epilogue
 1717     89/<- %esp 5/r32/ebp
 1718     5d/pop-to-ebp
 1719     c3/return
 1720 
 1721 test-read-output:
 1722     # also doesn't spill
 1723     # . prologue
 1724     55/push-ebp
 1725     89/<- %ebp 4/r32/esp
 1726     # setup
 1727     (clear-stream _test-input-stream)
 1728     (clear-stream $_test-input-buffered-file->buffer)
 1729     (clear-stream _test-output-stream)
 1730     (clear-stream $_test-output-buffered-file->buffer)
 1731     #
 1732     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 1733     (write _test-input-stream "  x <- copy 0x34\n")
 1734     (write _test-input-stream "  compare x, 0x35\n")
 1735     (write _test-input-stream "}\n")
 1736     # convert
 1737     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1738     (flush _test-output-buffered-file)
 1739 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1745     # check output
 1746     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 1747     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 1748     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 1749     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 1750     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 1751     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 1752     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 1753     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 1754     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 1755     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 1756     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 1757     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 1758     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 1759     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 1760     # . epilogue
 1761     89/<- %esp 5/r32/ebp
 1762     5d/pop-to-ebp
 1763     c3/return
 1764 
 1765 test-convert-function-with-branches-in-block:
 1766     # . prologue
 1767     55/push-ebp
 1768     89/<- %ebp 4/r32/esp
 1769     # setup
 1770     (clear-stream _test-input-stream)
 1771     (clear-stream $_test-input-buffered-file->buffer)
 1772     (clear-stream _test-output-stream)
 1773     (clear-stream $_test-output-buffered-file->buffer)
 1774     #
 1775     (write _test-input-stream "fn foo x: int {\n")
 1776     (write _test-input-stream "  {\n")
 1777     (write _test-input-stream "    break-if->=\n")
 1778     (write _test-input-stream "    loop-if-addr<\n")
 1779     (write _test-input-stream "    increment x\n")
 1780     (write _test-input-stream "    loop\n")
 1781     (write _test-input-stream "  }\n")
 1782     (write _test-input-stream "}\n")
 1783     # convert
 1784     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1785     (flush _test-output-buffered-file)
 1786 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1792     # check output
 1793     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 1794     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 1795     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 1796     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 1797     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 1798     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 1799     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 1800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 1801     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 1802     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 1803     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 1804     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 1805     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 1806     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 1807     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 1808     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 1809     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 1810     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 1811     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 1812     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 1813     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 1814     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 1815     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 1816     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 1817     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 1818     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 1819     # . epilogue
 1820     89/<- %esp 5/r32/ebp
 1821     5d/pop-to-ebp
 1822     c3/return
 1823 
 1824 test-convert-function-with-branches-in-named-block:
 1825     # . prologue
 1826     55/push-ebp
 1827     89/<- %ebp 4/r32/esp
 1828     # setup
 1829     (clear-stream _test-input-stream)
 1830     (clear-stream $_test-input-buffered-file->buffer)
 1831     (clear-stream _test-output-stream)
 1832     (clear-stream $_test-output-buffered-file->buffer)
 1833     #
 1834     (write _test-input-stream "fn foo x: int {\n")
 1835     (write _test-input-stream "  $bar: {\n")
 1836     (write _test-input-stream "    break-if->= $bar\n")
 1837     (write _test-input-stream "    loop-if-addr< $bar\n")
 1838     (write _test-input-stream "    increment x\n")
 1839     (write _test-input-stream "    loop\n")
 1840     (write _test-input-stream "  }\n")
 1841     (write _test-input-stream "}\n")
 1842     # convert
 1843     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1844     (flush _test-output-buffered-file)
 1845 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1851     # check output
 1852     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 1853     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 1854     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 1855     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 1856     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 1857     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 1858     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 1859     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 1860     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 1861     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 1862     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 1863     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 1864     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 1865     (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")
 1866     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 1867     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 1868     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 1869     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 1870     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 1871     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 1872     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 1873     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 1874     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 1875     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 1876     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 1877     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 1878     # . epilogue
 1879     89/<- %esp 5/r32/ebp
 1880     5d/pop-to-ebp
 1881     c3/return
 1882 
 1883 test-convert-function-with-var-in-nested-block:
 1884     # . prologue
 1885     55/push-ebp
 1886     89/<- %ebp 4/r32/esp
 1887     # setup
 1888     (clear-stream _test-input-stream)
 1889     (clear-stream $_test-input-buffered-file->buffer)
 1890     (clear-stream _test-output-stream)
 1891     (clear-stream $_test-output-buffered-file->buffer)
 1892     #
 1893     (write _test-input-stream "fn foo x: int {\n")
 1894     (write _test-input-stream "  {\n")
 1895     (write _test-input-stream "    {\n")
 1896     (write _test-input-stream "      var x: int\n")
 1897     (write _test-input-stream "      increment x\n")
 1898     (write _test-input-stream "    }\n")
 1899     (write _test-input-stream "  }\n")
 1900     (write _test-input-stream "}\n")
 1901     # convert
 1902     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1903     (flush _test-output-buffered-file)
 1904 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1910     # check output
 1911     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 1912     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 1913     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 1914     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 1915     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 1916     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 1917     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 1918     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 1919     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 1920     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 1921     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 1922     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 1923     (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")
 1924     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 1925     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 1926     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 1927     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 1928     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 1929     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 1930     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 1931     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 1932     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 1933     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 1934     # . epilogue
 1935     89/<- %esp 5/r32/ebp
 1936     5d/pop-to-ebp
 1937     c3/return
 1938 
 1939 test-convert-function-with-multiple-vars-in-nested-blocks:
 1940     # . prologue
 1941     55/push-ebp
 1942     89/<- %ebp 4/r32/esp
 1943     # setup
 1944     (clear-stream _test-input-stream)
 1945     (clear-stream $_test-input-buffered-file->buffer)
 1946     (clear-stream _test-output-stream)
 1947     (clear-stream $_test-output-buffered-file->buffer)
 1948     #
 1949     (write _test-input-stream "fn foo x: int {\n")
 1950     (write _test-input-stream "  {\n")
 1951     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 1952     (write _test-input-stream "    {\n")
 1953     (write _test-input-stream "      var y: int\n")
 1954     (write _test-input-stream "      x <- add y\n")
 1955     (write _test-input-stream "    }\n")
 1956     (write _test-input-stream "  }\n")
 1957     (write _test-input-stream "}\n")
 1958     # convert
 1959     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1960     (flush _test-output-buffered-file)
 1961 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1967     # check output
 1968     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 1969     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 1970     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 1971     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 1972     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 1973     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 1974     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 1975     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 1976     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 1977     (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")
 1978     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 1979     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 1980     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 1981     (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")
 1982     (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")
 1983     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 1984     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 1985     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 1986     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 1987     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 1988     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 1989     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 1990     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 1991     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 1992     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 1993     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 1994     # . epilogue
 1995     89/<- %esp 5/r32/ebp
 1996     5d/pop-to-ebp
 1997     c3/return
 1998 
 1999 test-convert-function-with-branches-and-local-vars:
 2000     # A conditional 'break' after a 'var' in a block is converted into a
 2001     # nested block that performs all necessary cleanup before jumping. This
 2002     # results in some ugly code duplication.
 2003     # . prologue
 2004     55/push-ebp
 2005     89/<- %ebp 4/r32/esp
 2006     # setup
 2007     (clear-stream _test-input-stream)
 2008     (clear-stream $_test-input-buffered-file->buffer)
 2009     (clear-stream _test-output-stream)
 2010     (clear-stream $_test-output-buffered-file->buffer)
 2011     #
 2012     (write _test-input-stream "fn foo {\n")
 2013     (write _test-input-stream "  {\n")
 2014     (write _test-input-stream "    var x: int\n")
 2015     (write _test-input-stream "    break-if->=\n")
 2016     (write _test-input-stream "    increment x\n")
 2017     (write _test-input-stream "  }\n")
 2018     (write _test-input-stream "}\n")
 2019     # convert
 2020     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2021     (flush _test-output-buffered-file)
 2022 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2028     # check output
 2029     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 2030     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 2031     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 2032     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 2033     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 2034     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 2035     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 2036     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 2037     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 2038     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 2039     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 2040     (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")
 2041     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 2042     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 2043     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 2044     (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")
 2045     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 2046     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 2047     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 2048     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 2049     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 2050     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 2051     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 2052     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 2053     # . epilogue
 2054     89/<- %esp 5/r32/ebp
 2055     5d/pop-to-ebp
 2056     c3/return
 2057 
 2058 test-convert-function-with-conditional-loops-and-local-vars:
 2059     # A conditional 'loop' after a 'var' in a block is converted into a nested
 2060     # block that performs all necessary cleanup before jumping. This results
 2061     # in some ugly code duplication.
 2062     # . prologue
 2063     55/push-ebp
 2064     89/<- %ebp 4/r32/esp
 2065     # setup
 2066     (clear-stream _test-input-stream)
 2067     (clear-stream $_test-input-buffered-file->buffer)
 2068     (clear-stream _test-output-stream)
 2069     (clear-stream $_test-output-buffered-file->buffer)
 2070     #
 2071     (write _test-input-stream "fn foo {\n")
 2072     (write _test-input-stream "  {\n")
 2073     (write _test-input-stream "    var x: int\n")
 2074     (write _test-input-stream "    loop-if->=\n")
 2075     (write _test-input-stream "    increment x\n")
 2076     (write _test-input-stream "  }\n")
 2077     (write _test-input-stream "}\n")
 2078     # convert
 2079     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2080     (flush _test-output-buffered-file)
 2081 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2087     # check output
 2088     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 2089     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 2090     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 2091     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 2092     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 2093     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 2094     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 2095     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 2096     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 2097     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 2098     (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")
 2099     (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")
 2100     (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")
 2101     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2102     (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")
 2103     (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")
 2104     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2105     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2106     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2107     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2108     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2109     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2110     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2111     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2112     # . epilogue
 2113     89/<- %esp 5/r32/ebp
 2114     5d/pop-to-ebp
 2115     c3/return
 2116 
 2117 test-convert-function-with-unconditional-loops-and-local-vars:
 2118     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2119     # regular block cleanup. Any instructions after 'loop' are dead and
 2120     # therefore skipped.
 2121     # . prologue
 2122     55/push-ebp
 2123     89/<- %ebp 4/r32/esp
 2124     # setup
 2125     (clear-stream _test-input-stream)
 2126     (clear-stream $_test-input-buffered-file->buffer)
 2127     (clear-stream _test-output-stream)
 2128     (clear-stream $_test-output-buffered-file->buffer)
 2129     #
 2130     (write _test-input-stream "fn foo {\n")
 2131     (write _test-input-stream "  {\n")
 2132     (write _test-input-stream "    var x: int\n")
 2133     (write _test-input-stream "    loop\n")
 2134     (write _test-input-stream "    increment x\n")
 2135     (write _test-input-stream "  }\n")
 2136     (write _test-input-stream "}\n")
 2137     # convert
 2138     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2139     (flush _test-output-buffered-file)
 2140 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2146     # check output
 2147     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2148     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2149     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2150     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2151     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2152     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2153     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2154     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2155     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2156     (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")
 2157     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2158     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2159     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2160     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2161     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2162     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2163     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2164     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2165     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2166     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2167     # . epilogue
 2168     89/<- %esp 5/r32/ebp
 2169     5d/pop-to-ebp
 2170     c3/return
 2171 
 2172 test-convert-function-with-branches-and-loops-and-local-vars:
 2173     # . prologue
 2174     55/push-ebp
 2175     89/<- %ebp 4/r32/esp
 2176     # setup
 2177     (clear-stream _test-input-stream)
 2178     (clear-stream $_test-input-buffered-file->buffer)
 2179     (clear-stream _test-output-stream)
 2180     (clear-stream $_test-output-buffered-file->buffer)
 2181     #
 2182     (write _test-input-stream "fn foo {\n")
 2183     (write _test-input-stream "  {\n")
 2184     (write _test-input-stream "    var x: int\n")
 2185     (write _test-input-stream "    break-if->=\n")
 2186     (write _test-input-stream "    increment x\n")
 2187     (write _test-input-stream "    loop\n")
 2188     (write _test-input-stream "  }\n")
 2189     (write _test-input-stream "}\n")
 2190     # convert
 2191     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2192     (flush _test-output-buffered-file)
 2193 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2199     # check output
 2200     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 2201     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 2202     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 2203     (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")
 2204     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 2205     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 2206     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 2207     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 2208     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 2209     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 2210     (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")
 2211     (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")
 2212     (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")
 2213     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 2214     (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")
 2215     (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")
 2216     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 2217     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 2218     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 2219     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 2220     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 2221     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 2222     (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")
 2223     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 2224     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 2225     # . epilogue
 2226     89/<- %esp 5/r32/ebp
 2227     5d/pop-to-ebp
 2228     c3/return
 2229 
 2230 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 2231     # . prologue
 2232     55/push-ebp
 2233     89/<- %ebp 4/r32/esp
 2234     # setup
 2235     (clear-stream _test-input-stream)
 2236     (clear-stream $_test-input-buffered-file->buffer)
 2237     (clear-stream _test-output-stream)
 2238     (clear-stream $_test-output-buffered-file->buffer)
 2239     #
 2240     (write _test-input-stream "fn foo {\n")
 2241     (write _test-input-stream "  a: {\n")
 2242     (write _test-input-stream "    var x: int\n")
 2243     (write _test-input-stream "    {\n")
 2244     (write _test-input-stream "      var y: int\n")
 2245     (write _test-input-stream "      break-if->= a\n")
 2246     (write _test-input-stream "      increment x\n")
 2247     (write _test-input-stream "      loop\n")
 2248     (write _test-input-stream "    }\n")
 2249     (write _test-input-stream "  }\n")
 2250     (write _test-input-stream "}\n")
 2251     # convert
 2252     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2253     (flush _test-output-buffered-file)
 2254 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2260     # check output
 2261     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 2262     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 2263     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 2264     (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")
 2265     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 2266     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 2267     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 2268     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 2269     (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")
 2270     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 2271     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 2272     (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")
 2273     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 2274     (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")
 2275     (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")
 2276     (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")
 2277     (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")
 2278     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 2279     (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")
 2280     (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")
 2281     (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")
 2282     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 2283     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 2284     (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")
 2285     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 2286     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 2287     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 2288     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 2289     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 2290     (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")
 2291     (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")
 2292     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 2293     # . epilogue
 2294     89/<- %esp 5/r32/ebp
 2295     5d/pop-to-ebp
 2296     c3/return
 2297 
 2298 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 2299     # . prologue
 2300     55/push-ebp
 2301     89/<- %ebp 4/r32/esp
 2302     # setup
 2303     (clear-stream _test-input-stream)
 2304     (clear-stream $_test-input-buffered-file->buffer)
 2305     (clear-stream _test-output-stream)
 2306     (clear-stream $_test-output-buffered-file->buffer)
 2307     # non-local conditional branch from a block without a local variable,
 2308     # unwinding a local on the stack
 2309     (write _test-input-stream "fn foo {\n")
 2310     (write _test-input-stream "  a: {\n")
 2311     (write _test-input-stream "    var x: int\n")
 2312     (write _test-input-stream "    {\n")
 2313     (write _test-input-stream "      break-if->= a\n")
 2314     (write _test-input-stream "    }\n")
 2315     (write _test-input-stream "  }\n")
 2316     (write _test-input-stream "}\n")
 2317     # convert
 2318     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2319     (flush _test-output-buffered-file)
 2320 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2326     # check output
 2327     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 2328     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 2329     (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")
 2330     (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")
 2331     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 2332     (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")
 2333     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 2334     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 2335     (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")
 2336     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 2337     (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")
 2338     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 2339     (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")
 2340     (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")
 2341     (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")
 2342     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 2343     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 2344     (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")
 2345     (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")
 2346     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 2347     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 2348     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 2349     (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")
 2350     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 2351     (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")
 2352     (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")
 2353     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 2354     # . epilogue
 2355     89/<- %esp 5/r32/ebp
 2356     5d/pop-to-ebp
 2357     c3/return
 2358 
 2359 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 2360     # . prologue
 2361     55/push-ebp
 2362     89/<- %ebp 4/r32/esp
 2363     # setup
 2364     (clear-stream _test-input-stream)
 2365     (clear-stream $_test-input-buffered-file->buffer)
 2366     (clear-stream _test-output-stream)
 2367     (clear-stream $_test-output-buffered-file->buffer)
 2368     # non-local unconditional branch from a block without a local variable,
 2369     # unwinding a local on the stack
 2370     (write _test-input-stream "fn foo {\n")
 2371     (write _test-input-stream "  a: {\n")
 2372     (write _test-input-stream "    var x: int\n")
 2373     (write _test-input-stream "    {\n")
 2374     (write _test-input-stream "      break a\n")
 2375     (write _test-input-stream "    }\n")
 2376     (write _test-input-stream "  }\n")
 2377     (write _test-input-stream "}\n")
 2378     # convert
 2379     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2380     (flush _test-output-buffered-file)
 2381 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2387     # check output
 2388     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 2389     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 2390     (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")
 2391     (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")
 2392     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 2393     (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")
 2394     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 2395     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 2396     (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")
 2397     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 2398     (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")
 2399     (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")
 2400     (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")
 2401     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 2402     (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")
 2403     (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")
 2404     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 2405     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 2406     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 2407     (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")
 2408     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 2409     (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")
 2410     (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")
 2411     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 2412     # . epilogue
 2413     89/<- %esp 5/r32/ebp
 2414     5d/pop-to-ebp
 2415     c3/return
 2416 
 2417 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 2418     # . prologue
 2419     55/push-ebp
 2420     89/<- %ebp 4/r32/esp
 2421     # setup
 2422     (clear-stream _test-input-stream)
 2423     (clear-stream $_test-input-buffered-file->buffer)
 2424     (clear-stream _test-output-stream)
 2425     (clear-stream $_test-output-buffered-file->buffer)
 2426     #
 2427     (write _test-input-stream "fn foo {\n")
 2428     (write _test-input-stream "  a: {\n")
 2429     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 2430     (write _test-input-stream "    {\n")
 2431     (write _test-input-stream "      break a\n")
 2432     (write _test-input-stream "    }\n")
 2433     (write _test-input-stream "  }\n")
 2434     (write _test-input-stream "}\n")
 2435     # convert
 2436     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2437     (flush _test-output-buffered-file)
 2438 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2444     # check output
 2445     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 2446     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 2447     (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")
 2448     (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")
 2449     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 2450     (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")
 2451     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 2452     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 2453     (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")
 2454     (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")
 2455     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 2456     (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")
 2457     (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")
 2458     (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")
 2459     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 2460     (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")
 2461     (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")
 2462     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 2463     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 2464     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 2465     (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")
 2466     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 2467     (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")
 2468     (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")
 2469     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 2470     # . epilogue
 2471     89/<- %esp 5/r32/ebp
 2472     5d/pop-to-ebp
 2473     c3/return
 2474 
 2475 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 2476     # . prologue
 2477     55/push-ebp
 2478     89/<- %ebp 4/r32/esp
 2479     # setup
 2480     (clear-stream _test-input-stream)
 2481     (clear-stream $_test-input-buffered-file->buffer)
 2482     (clear-stream _test-output-stream)
 2483     (clear-stream $_test-output-buffered-file->buffer)
 2484     #
 2485     (write _test-input-stream "fn foo {\n")
 2486     (write _test-input-stream "  a: {\n")
 2487     (write _test-input-stream "    var x: int\n")
 2488     (write _test-input-stream "    {\n")
 2489     (write _test-input-stream "      var y: int\n")
 2490     (write _test-input-stream "      break a\n")
 2491     (write _test-input-stream "      increment x\n")
 2492     (write _test-input-stream "    }\n")
 2493     (write _test-input-stream "  }\n")
 2494     (write _test-input-stream "}\n")
 2495     # convert
 2496     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2497     (flush _test-output-buffered-file)
 2498 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2504     # check output
 2505     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 2506     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 2507     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 2508     (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")
 2509     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 2510     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 2511     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 2512     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 2513     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 2514     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 2515     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 2516     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 2517     (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")
 2518     (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")
 2519     (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")
 2520     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 2521     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 2522     (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")
 2523     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 2524     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 2525     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 2526     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 2527     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 2528     (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")
 2529     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 2530     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 2531     # . epilogue
 2532     89/<- %esp 5/r32/ebp
 2533     5d/pop-to-ebp
 2534     c3/return
 2535 
 2536 test-convert-function-with-unconditional-break-and-local-vars:
 2537     # . prologue
 2538     55/push-ebp
 2539     89/<- %ebp 4/r32/esp
 2540     # setup
 2541     (clear-stream _test-input-stream)
 2542     (clear-stream $_test-input-buffered-file->buffer)
 2543     (clear-stream _test-output-stream)
 2544     (clear-stream $_test-output-buffered-file->buffer)
 2545     #
 2546     (write _test-input-stream "fn foo {\n")
 2547     (write _test-input-stream "  {\n")
 2548     (write _test-input-stream "    var x: int\n")
 2549     (write _test-input-stream "    {\n")
 2550     (write _test-input-stream "      var y: int\n")
 2551     (write _test-input-stream "      break\n")
 2552     (write _test-input-stream "      increment x\n")
 2553     (write _test-input-stream "    }\n")
 2554     (write _test-input-stream "  }\n")
 2555     (write _test-input-stream "}\n")
 2556     # convert
 2557     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2558     (flush _test-output-buffered-file)
 2559 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2565     # check output
 2566     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 2567     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 2568     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 2569     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 2570     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 2571     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 2572     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 2573     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 2574     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 2575     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 2576     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 2577     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 2578     (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")
 2579     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 2580     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 2581     (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")
 2582     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 2583     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 2584     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 2585     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 2586     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 2587     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 2588     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 2589     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 2590     # . epilogue
 2591     89/<- %esp 5/r32/ebp
 2592     5d/pop-to-ebp
 2593     c3/return
 2594 
 2595 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 2596     # . prologue
 2597     55/push-ebp
 2598     89/<- %ebp 4/r32/esp
 2599     # setup
 2600     (clear-stream _test-input-stream)
 2601     (clear-stream $_test-input-buffered-file->buffer)
 2602     (clear-stream _test-output-stream)
 2603     (clear-stream $_test-output-buffered-file->buffer)
 2604     #
 2605     (write _test-input-stream "fn foo {\n")
 2606     (write _test-input-stream "  a: {\n")
 2607     (write _test-input-stream "    var x: int\n")
 2608     (write _test-input-stream "    {\n")
 2609     (write _test-input-stream "      var y: int\n")
 2610     (write _test-input-stream "      loop a\n")
 2611     (write _test-input-stream "      increment x\n")
 2612     (write _test-input-stream "    }\n")
 2613     (write _test-input-stream "  }\n")
 2614     (write _test-input-stream "}\n")
 2615     # convert
 2616     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2617     (flush _test-output-buffered-file)
 2618 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2624     # check output
 2625     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 2626     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 2627     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 2628     (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")
 2629     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 2630     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 2631     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 2632     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 2633     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 2634     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 2635     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 2636     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 2637     (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")
 2638     (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")
 2639     (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")
 2640     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 2641     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 2642     (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")
 2643     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 2644     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 2645     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 2646     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 2647     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 2648     (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")
 2649     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 2650     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 2651     # . epilogue
 2652     89/<- %esp 5/r32/ebp
 2653     5d/pop-to-ebp
 2654     c3/return
 2655 
 2656 test-convert-function-with-local-array-var-in-mem:
 2657     # . prologue
 2658     55/push-ebp
 2659     89/<- %ebp 4/r32/esp
 2660     # setup
 2661     (clear-stream _test-input-stream)
 2662     (clear-stream $_test-input-buffered-file->buffer)
 2663     (clear-stream _test-output-stream)
 2664     (clear-stream $_test-output-buffered-file->buffer)
 2665     #
 2666     (write _test-input-stream "fn foo {\n")
 2667     (write _test-input-stream "  var x: (array int 3)\n")
 2668     (write _test-input-stream "}\n")
 2669     # convert
 2670     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2671     (flush _test-output-buffered-file)
 2672 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2678     # check output
 2679     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 2680     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 2681     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 2682     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 2683     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 2684     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 2685     # define x
 2686     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 2687     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 2688     # reclaim x
 2689     (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")
 2690     #
 2691     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 2692     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 2693     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 2694     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 2695     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 2696     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 2697     # . epilogue
 2698     89/<- %esp 5/r32/ebp
 2699     5d/pop-to-ebp
 2700     c3/return
 2701 
 2702 test-convert-address:
 2703     # . prologue
 2704     55/push-ebp
 2705     89/<- %ebp 4/r32/esp
 2706     # setup
 2707     (clear-stream _test-input-stream)
 2708     (clear-stream $_test-input-buffered-file->buffer)
 2709     (clear-stream _test-output-stream)
 2710     (clear-stream $_test-output-buffered-file->buffer)
 2711     #
 2712     (write _test-input-stream "fn foo {\n")
 2713     (write _test-input-stream "  var a: int\n")
 2714     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 2715     (write _test-input-stream "}\n")
 2716     # convert
 2717     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2718     (flush _test-output-buffered-file)
 2719 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2725     # check output
 2726     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 2727     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 2728     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 2729     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 2730     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 2731     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 2732     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 2733     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 2734     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 2735     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 2736     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 2737     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 2738     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 2739     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 2740     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 2741     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 2742     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 2743     # . epilogue
 2744     89/<- %esp 5/r32/ebp
 2745     5d/pop-to-ebp
 2746     c3/return
 2747 
 2748 test-convert-length-of-array:
 2749     # . prologue
 2750     55/push-ebp
 2751     89/<- %ebp 4/r32/esp
 2752     # setup
 2753     (clear-stream _test-input-stream)
 2754     (clear-stream $_test-input-buffered-file->buffer)
 2755     (clear-stream _test-output-stream)
 2756     (clear-stream $_test-output-buffered-file->buffer)
 2757     #
 2758     (write _test-input-stream "fn foo a: (addr array int) {\n")
 2759     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 2760     (write _test-input-stream "  var c/eax: int <- length b\n")
 2761     (write _test-input-stream "}\n")
 2762     # convert
 2763     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2764     (flush _test-output-buffered-file)
 2765 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2771     # check output
 2772     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 2773     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 2774     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 2775     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 2776     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 2777     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 2778     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 2779     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 2780     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 2781     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 2782     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 2783     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 2784     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 2785     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 2786     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 2787     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 2788     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 2789     # . epilogue
 2790     89/<- %esp 5/r32/ebp
 2791     5d/pop-to-ebp
 2792     c3/return
 2793 
 2794 test-convert-length-of-array-on-stack:
 2795     # . prologue
 2796     55/push-ebp
 2797     89/<- %ebp 4/r32/esp
 2798     # setup
 2799     (clear-stream _test-input-stream)
 2800     (clear-stream $_test-input-buffered-file->buffer)
 2801     (clear-stream _test-output-stream)
 2802     (clear-stream $_test-output-buffered-file->buffer)
 2803     #
 2804     (write _test-input-stream "fn foo {\n")
 2805     (write _test-input-stream "  var a: (array int 3)\n")
 2806     (write _test-input-stream "  var b/eax: int <- length a\n")
 2807     (write _test-input-stream "}\n")
 2808     # convert
 2809     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2810     (flush _test-output-buffered-file)
 2811 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2817     # check output
 2818     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 2819     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 2820     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 2821     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 2822     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 2823     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 2824     # define x
 2825     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 2826     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 2827     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 2828     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 2829     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 2830     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 2831     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 2832     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 2833     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 2834     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 2835     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 2836     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 2837     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 2838     # . epilogue
 2839     89/<- %esp 5/r32/ebp
 2840     5d/pop-to-ebp
 2841     c3/return
 2842 
 2843 test-convert-index-into-array:
 2844     # . prologue
 2845     55/push-ebp
 2846     89/<- %ebp 4/r32/esp
 2847     # setup
 2848     (clear-stream _test-input-stream)
 2849     (clear-stream $_test-input-buffered-file->buffer)
 2850     (clear-stream _test-output-stream)
 2851     (clear-stream $_test-output-buffered-file->buffer)
 2852     #
 2853     (write _test-input-stream "fn foo {\n")
 2854     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2855     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 2856     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2857     (write _test-input-stream "}\n")
 2858     # convert
 2859     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2860     (flush _test-output-buffered-file)
 2861 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2867     # check output
 2868     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 2869     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 2870     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 2871     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 2872     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 2873     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 2874     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 2875     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 2876     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 2877     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 2878     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/11")
 2879     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/13")
 2880     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/14")
 2881     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/15")
 2882     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/16")
 2883     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/17")
 2884     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/18")
 2885     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/19")
 2886     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/20")
 2887     # . epilogue
 2888     89/<- %esp 5/r32/ebp
 2889     5d/pop-to-ebp
 2890     c3/return
 2891 
 2892 test-convert-index-into-array-with-literal:
 2893     # . prologue
 2894     55/push-ebp
 2895     89/<- %ebp 4/r32/esp
 2896     # setup
 2897     (clear-stream _test-input-stream)
 2898     (clear-stream $_test-input-buffered-file->buffer)
 2899     (clear-stream _test-output-stream)
 2900     (clear-stream $_test-output-buffered-file->buffer)
 2901     #
 2902     (write _test-input-stream "fn foo {\n")
 2903     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 2904     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 2905     (write _test-input-stream "}\n")
 2906     # convert
 2907     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2908     (flush _test-output-buffered-file)
 2909 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2915     # check output
 2916     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 2917     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 2918     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 2919     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 2920     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 2921     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 2922     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 2923     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 2924                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 2925     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 2926     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 2927     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 2928     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 2929     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 2930     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 2931     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 2932     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 2933     # . epilogue
 2934     89/<- %esp 5/r32/ebp
 2935     5d/pop-to-ebp
 2936     c3/return
 2937 
 2938 test-convert-index-into-array-on-stack:
 2939     # . prologue
 2940     55/push-ebp
 2941     89/<- %ebp 4/r32/esp
 2942     # setup
 2943     (clear-stream _test-input-stream)
 2944     (clear-stream $_test-input-buffered-file->buffer)
 2945     (clear-stream _test-output-stream)
 2946     (clear-stream $_test-output-buffered-file->buffer)
 2947     #
 2948     (write _test-input-stream "fn foo {\n")
 2949     (write _test-input-stream "  var arr: (array int 3)\n")
 2950     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 2951     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 2952     (write _test-input-stream "}\n")
 2953     # convert
 2954     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2955     (flush _test-output-buffered-file)
 2956 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2962     # check output
 2963     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 2964     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 2965     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 2966     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 2967     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 2968     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 2969     # var arr
 2970     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 2971     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 2972     # var idx
 2973     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 2974     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 2975     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 2976     (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")
 2977     # reclaim idx
 2978     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 2979     # reclaim arr
 2980     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 2981     #
 2982     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 2983     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 2984     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 2985     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 2986     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 2987     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 2988     # . epilogue
 2989     89/<- %esp 5/r32/ebp
 2990     5d/pop-to-ebp
 2991     c3/return
 2992 
 2993 test-convert-index-into-array-on-stack-with-literal:
 2994     # . prologue
 2995     55/push-ebp
 2996     89/<- %ebp 4/r32/esp
 2997     # setup
 2998     (clear-stream _test-input-stream)
 2999     (clear-stream $_test-input-buffered-file->buffer)
 3000     (clear-stream _test-output-stream)
 3001     (clear-stream $_test-output-buffered-file->buffer)
 3002     #
 3003     (write _test-input-stream "fn foo {\n")
 3004     (write _test-input-stream "  var arr: (array int 3)\n")
 3005     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3006     (write _test-input-stream "}\n")
 3007     # convert
 3008     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3009     (flush _test-output-buffered-file)
 3010 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3016     # check output
 3017     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 3018     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 3019     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 3020     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 3021     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 3022     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 3023     # var arr
 3024     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 3025     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 3026     # var x
 3027     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 3028     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 3029     (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")
 3030     # reclaim x
 3031     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 3032     # reclaim arr
 3033     (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")
 3034     #
 3035     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 3036     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 3037     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 3038     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 3039     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 3040     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 3041     # . epilogue
 3042     89/<- %esp 5/r32/ebp
 3043     5d/pop-to-ebp
 3044     c3/return
 3045 
 3046 test-convert-index-into-array-using-offset:
 3047     # . prologue
 3048     55/push-ebp
 3049     89/<- %ebp 4/r32/esp
 3050     # setup
 3051     (clear-stream _test-input-stream)
 3052     (clear-stream $_test-input-buffered-file->buffer)
 3053     (clear-stream _test-output-stream)
 3054     (clear-stream $_test-output-buffered-file->buffer)
 3055     #
 3056     (write _test-input-stream "fn foo {\n")
 3057     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3058     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3059     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 3060     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 3061     (write _test-input-stream "}\n")
 3062     # convert
 3063     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3064     (flush _test-output-buffered-file)
 3065 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3071     # check output
 3072     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 3073     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 3074     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 3075     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 3076     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 3077     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 3078     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 3079     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 3080     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 3081     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 3082     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 3083     (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")
 3084     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 3085     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 3086     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 3087     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 3088     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 3089     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 3090     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 3091     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 3092     # . epilogue
 3093     89/<- %esp 5/r32/ebp
 3094     5d/pop-to-ebp
 3095     c3/return
 3096 
 3097 test-convert-index-into-array-using-offset-on-stack:
 3098     # . prologue
 3099     55/push-ebp
 3100     89/<- %ebp 4/r32/esp
 3101     # setup
 3102     (clear-stream _test-input-stream)
 3103     (clear-stream $_test-input-buffered-file->buffer)
 3104     (clear-stream _test-output-stream)
 3105     (clear-stream $_test-output-buffered-file->buffer)
 3106     #
 3107     (write _test-input-stream "fn foo {\n")
 3108     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3109     (write _test-input-stream "  var idx: int\n")
 3110     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 3111     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 3112     (write _test-input-stream "}\n")
 3113     # convert
 3114     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3115     (flush _test-output-buffered-file)
 3116 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3122     # check output
 3123     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 3124     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 3125     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 3126     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 3127     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 3128     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 3129     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 3130     (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")
 3131     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 3132     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 3133     (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")
 3134     (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")
 3135     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 3136     (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")
 3137     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 3138     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 3139     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 3140     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 3141     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 3142     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 3143     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 3144     # . epilogue
 3145     89/<- %esp 5/r32/ebp
 3146     5d/pop-to-ebp
 3147     c3/return
 3148 
 3149 test-convert-function-and-type-definition:
 3150     # . prologue
 3151     55/push-ebp
 3152     89/<- %ebp 4/r32/esp
 3153     # setup
 3154     (clear-stream _test-input-stream)
 3155     (clear-stream $_test-input-buffered-file->buffer)
 3156     (clear-stream _test-output-stream)
 3157     (clear-stream $_test-output-buffered-file->buffer)
 3158     #
 3159     (write _test-input-stream "fn foo a: (addr t) {\n")
 3160     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 3161     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 3162     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 3163     (write _test-input-stream "}\n")
 3164     (write _test-input-stream "type t {\n")
 3165     (write _test-input-stream "  x: int\n")
 3166     (write _test-input-stream "  y: int\n")
 3167     (write _test-input-stream "}\n")
 3168     # convert
 3169     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3170     (flush _test-output-buffered-file)
 3171 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3177     # check output
 3178     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 3179     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 3180     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 3181     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 3182     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 3183     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 3184     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 3185     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 3186     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 3187     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 3188     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 3189     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 3190     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 3191     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 3192     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 3193     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 3194     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 3195     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 3196     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 3197     # . epilogue
 3198     89/<- %esp 5/r32/ebp
 3199     5d/pop-to-ebp
 3200     c3/return
 3201 
 3202 test-convert-function-with-local-var-with-user-defined-type:
 3203     # . prologue
 3204     55/push-ebp
 3205     89/<- %ebp 4/r32/esp
 3206     # setup
 3207     (clear-stream _test-input-stream)
 3208     (clear-stream $_test-input-buffered-file->buffer)
 3209     (clear-stream _test-output-stream)
 3210     (clear-stream $_test-output-buffered-file->buffer)
 3211     #
 3212     (write _test-input-stream "fn foo {\n")
 3213     (write _test-input-stream "  var a: t\n")
 3214     (write _test-input-stream "}\n")
 3215     (write _test-input-stream "type t {\n")
 3216     (write _test-input-stream "  x: int\n")
 3217     (write _test-input-stream "  y: int\n")
 3218     (write _test-input-stream "}\n")
 3219     # convert
 3220     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3221     (flush _test-output-buffered-file)
 3222 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3228     # check output
 3229     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 3230     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 3231     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 3232     (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")
 3233     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 3234     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 3235     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 3236     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 3237     (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")
 3238     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 3239     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 3240     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 3241     (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")
 3242     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 3243     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 3244     # . epilogue
 3245     89/<- %esp 5/r32/ebp
 3246     5d/pop-to-ebp
 3247     c3/return
 3248 
 3249 test-convert-function-call-with-arg-of-user-defined-type:
 3250     # . prologue
 3251     55/push-ebp
 3252     89/<- %ebp 4/r32/esp
 3253     # setup
 3254     (clear-stream _test-input-stream)
 3255     (clear-stream $_test-input-buffered-file->buffer)
 3256     (clear-stream _test-output-stream)
 3257     (clear-stream $_test-output-buffered-file->buffer)
 3258     #
 3259     (write _test-input-stream "fn f {\n")
 3260     (write _test-input-stream "  var a: t\n")
 3261     (write _test-input-stream "  foo a\n")
 3262     (write _test-input-stream "}\n")
 3263     (write _test-input-stream "fn foo x: t {\n")
 3264     (write _test-input-stream "}\n")
 3265     (write _test-input-stream "type t {\n")
 3266     (write _test-input-stream "  x: int\n")
 3267     (write _test-input-stream "  y: int\n")
 3268     (write _test-input-stream "}\n")
 3269     # convert
 3270     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3271     (flush _test-output-buffered-file)
 3272 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3278     # check output
 3279     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 3280     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 3281     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 3282     (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")
 3283     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 3284     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 3285     # var a: t
 3286     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 3287     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 3288     # foo a
 3289     (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")
 3290     #
 3291     (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")
 3292     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 3293     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 3294     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 3295     (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")
 3296     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 3297     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 3298     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 3299     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 3300     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 3301     (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")
 3302     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 3303     (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")
 3304     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 3305     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 3306     # . epilogue
 3307     89/<- %esp 5/r32/ebp
 3308     5d/pop-to-ebp
 3309     c3/return
 3310 
 3311 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 3312     # . prologue
 3313     55/push-ebp
 3314     89/<- %ebp 4/r32/esp
 3315     # setup
 3316     (clear-stream _test-input-stream)
 3317     (clear-stream $_test-input-buffered-file->buffer)
 3318     (clear-stream _test-output-stream)
 3319     (clear-stream $_test-output-buffered-file->buffer)
 3320     #
 3321     (write _test-input-stream "fn f {\n")
 3322     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 3323     (write _test-input-stream "  foo *a\n")
 3324     (write _test-input-stream "}\n")
 3325     (write _test-input-stream "fn foo x: t {\n")
 3326     (write _test-input-stream "}\n")
 3327     (write _test-input-stream "type t {\n")
 3328     (write _test-input-stream "  x: int\n")
 3329     (write _test-input-stream "  y: int\n")
 3330     (write _test-input-stream "}\n")
 3331     # convert
 3332     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3333     (flush _test-output-buffered-file)
 3334 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3340     # check output
 3341     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 3342     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 3343     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 3344     (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")
 3345     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 3346     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 3347     # var a
 3348     (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")
 3349     (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")
 3350     # foo a
 3351     (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")
 3352     #
 3353     (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")
 3354     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 3355     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 3356     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 3357     (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")
 3358     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 3359     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 3360     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 3361     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 3362     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 3363     (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")
 3364     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 3365     (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")
 3366     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 3367     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 3368     # . epilogue
 3369     89/<- %esp 5/r32/ebp
 3370     5d/pop-to-ebp
 3371     c3/return
 3372 
 3373 # we don't have special support for call-by-reference; just explicitly create
 3374 # a new variable with the address of the arg
 3375 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 3376     # . prologue
 3377     55/push-ebp
 3378     89/<- %ebp 4/r32/esp
 3379     # setup
 3380     (clear-stream _test-input-stream)
 3381     (clear-stream $_test-input-buffered-file->buffer)
 3382     (clear-stream _test-output-stream)
 3383     (clear-stream $_test-output-buffered-file->buffer)
 3384     #
 3385     (write _test-input-stream "fn f {\n")
 3386     (write _test-input-stream "  var a: t\n")
 3387     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 3388     (write _test-input-stream "  foo b\n")
 3389     (write _test-input-stream "}\n")
 3390     (write _test-input-stream "fn foo x: (addr t) {\n")
 3391     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 3392     (write _test-input-stream "  increment *x\n")
 3393     (write _test-input-stream "}\n")
 3394     (write _test-input-stream "type t {\n")
 3395     (write _test-input-stream "  x: int\n")
 3396     (write _test-input-stream "  y: int\n")
 3397     (write _test-input-stream "}\n")
 3398     # convert
 3399     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3400     (flush _test-output-buffered-file)
 3401 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3407     # check output
 3408     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 3409     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 3410     (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")
 3411     (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")
 3412     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 3413     (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")
 3414     # var a: t
 3415     (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")
 3416     (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")
 3417     # var b/eax: (addr t)
 3418     (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")
 3419     (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")
 3420     # foo a
 3421     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 3422     #
 3423     (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")
 3424     (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")
 3425     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 3426     (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")
 3427     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 3428     (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")
 3429     (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")
 3430     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 3431     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 3432     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 3433     (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")
 3434     (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")
 3435     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 3436     (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")
 3437     (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")
 3438     (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")
 3439     (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")
 3440     (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")
 3441     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 3442     (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")
 3443     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 3444     (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")
 3445     (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")
 3446     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 3447     # . epilogue
 3448     89/<- %esp 5/r32/ebp
 3449     5d/pop-to-ebp
 3450     c3/return
 3451 
 3452 test-convert-get-on-local-variable:
 3453     # . prologue
 3454     55/push-ebp
 3455     89/<- %ebp 4/r32/esp
 3456     # setup
 3457     (clear-stream _test-input-stream)
 3458     (clear-stream $_test-input-buffered-file->buffer)
 3459     (clear-stream _test-output-stream)
 3460     (clear-stream $_test-output-buffered-file->buffer)
 3461     #
 3462     (write _test-input-stream "fn foo {\n")
 3463     (write _test-input-stream "  var a: t\n")
 3464     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3465     (write _test-input-stream "}\n")
 3466     (write _test-input-stream "type t {\n")
 3467     (write _test-input-stream "  x: int\n")
 3468     (write _test-input-stream "  y: int\n")
 3469     (write _test-input-stream "}\n")
 3470     # convert
 3471     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3472     (flush _test-output-buffered-file)
 3473 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3479     # check output
 3480     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 3481     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 3482     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 3483     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 3484     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 3485     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 3486     # var a
 3487     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 3488     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 3489     # var c
 3490     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 3491     # get
 3492     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 3493     # reclaim c
 3494     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 3495     # reclaim a
 3496     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 3497     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 3498     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 3499     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 3500     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 3501     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 3502     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 3503     # . epilogue
 3504     89/<- %esp 5/r32/ebp
 3505     5d/pop-to-ebp
 3506     c3/return
 3507 
 3508 test-convert-get-on-function-argument:
 3509     # . prologue
 3510     55/push-ebp
 3511     89/<- %ebp 4/r32/esp
 3512     # setup
 3513     (clear-stream _test-input-stream)
 3514     (clear-stream $_test-input-buffered-file->buffer)
 3515     (clear-stream _test-output-stream)
 3516     (clear-stream $_test-output-buffered-file->buffer)
 3517     #
 3518     (write _test-input-stream "fn foo a: t {\n")
 3519     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3520     (write _test-input-stream "}\n")
 3521     (write _test-input-stream "type t {\n")
 3522     (write _test-input-stream "  x: int\n")
 3523     (write _test-input-stream "  y: int\n")
 3524     (write _test-input-stream "}\n")
 3525     # convert
 3526     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3527     (flush _test-output-buffered-file)
 3528 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3534     # check output
 3535     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 3536     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 3537     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 3538     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 3539     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 3540     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 3541     # var c
 3542     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 3543     # get
 3544     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 3545     # reclaim c
 3546     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 3547     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 3548     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 3549     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 3550     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 3551     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 3552     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 3553     # . epilogue
 3554     89/<- %esp 5/r32/ebp
 3555     5d/pop-to-ebp
 3556     c3/return
 3557 
 3558 test-convert-get-on-function-argument-with-known-type:
 3559     # . prologue
 3560     55/push-ebp
 3561     89/<- %ebp 4/r32/esp
 3562     # setup
 3563     (clear-stream _test-input-stream)
 3564     (clear-stream $_test-input-buffered-file->buffer)
 3565     (clear-stream _test-output-stream)
 3566     (clear-stream $_test-output-buffered-file->buffer)
 3567     #
 3568     (write _test-input-stream "type t {\n")
 3569     (write _test-input-stream "  x: int\n")
 3570     (write _test-input-stream "  y: int\n")
 3571     (write _test-input-stream "}\n")
 3572     (write _test-input-stream "fn foo a: t {\n")
 3573     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3574     (write _test-input-stream "}\n")
 3575     # convert
 3576     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3577     (flush _test-output-buffered-file)
 3578 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3584     # check output
 3585     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 3586     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 3587     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 3588     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 3589     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 3590     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 3591     # var c
 3592     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 3593     # get
 3594     (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")
 3595     # reclaim c
 3596     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 3597     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 3598     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 3599     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 3600     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 3601     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 3602     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 3603     # . epilogue
 3604     89/<- %esp 5/r32/ebp
 3605     5d/pop-to-ebp
 3606     c3/return
 3607 
 3608 test-get-with-wrong-field:
 3609     # . prologue
 3610     55/push-ebp
 3611     89/<- %ebp 4/r32/esp
 3612     # setup
 3613     (clear-stream _test-input-stream)
 3614     (clear-stream $_test-input-buffered-file->buffer)
 3615     (clear-stream _test-output-stream)
 3616     (clear-stream $_test-output-buffered-file->buffer)
 3617     (clear-stream _test-error-stream)
 3618     (clear-stream $_test-error-buffered-file->buffer)
 3619     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 3620     68/push 0/imm32
 3621     68/push 0/imm32
 3622     89/<- %edx 4/r32/esp
 3623     (tailor-exit-descriptor %edx 0x10)
 3624     #
 3625     (write _test-input-stream "fn foo {\n")
 3626     (write _test-input-stream "  var a: t\n")
 3627     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 3628     (write _test-input-stream "}\n")
 3629     (write _test-input-stream "type t {\n")
 3630     (write _test-input-stream "  x: int\n")
 3631     (write _test-input-stream "}\n")
 3632     # convert
 3633     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3634     # registers except esp clobbered at this point
 3635     # restore ed
 3636     89/<- %edx 4/r32/esp
 3637     (flush _test-output-buffered-file)
 3638     (flush _test-error-buffered-file)
 3639 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 3645     # check output
 3646     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 3647     (check-next-stream-line-equal _test-error-stream  "type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
 3648     # check that stop(1) was called
 3649     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 3650     # don't restore from ebp
 3651     81 0/subop/add %esp 8/imm32
 3652     # . epilogue
 3653     5d/pop-to-ebp
 3654     c3/return
 3655 
 3656 test-convert-array-of-user-defined-types:
 3657     # . prologue
 3658     55/push-ebp
 3659     89/<- %ebp 4/r32/esp
 3660     # setup
 3661     (clear-stream _test-input-stream)
 3662     (clear-stream $_test-input-buffered-file->buffer)
 3663     (clear-stream _test-output-stream)
 3664     (clear-stream $_test-output-buffered-file->buffer)
 3665     #
 3666     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3667     (write _test-input-stream "  x: int\n")
 3668     (write _test-input-stream "  y: int\n")
 3669     (write _test-input-stream "}\n")
 3670     (write _test-input-stream "fn foo {\n")
 3671     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3672     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3673     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3674     (write _test-input-stream "}\n")
 3675     # convert
 3676     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3677     (flush _test-output-buffered-file)
 3678 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3684     # check output
 3685     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 3686     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 3687     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 3688     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 3689     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 3690     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 3691     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 3692     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 3693     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 3694     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 3695     (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")
 3696     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 3697     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 3698     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 3699     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 3700     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 3701     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 3702     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 3703     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 3704     # . epilogue
 3705     89/<- %esp 5/r32/ebp
 3706     5d/pop-to-ebp
 3707     c3/return
 3708 
 3709 test-convert-length-of-array-of-user-defined-types-to-eax:
 3710     # . prologue
 3711     55/push-ebp
 3712     89/<- %ebp 4/r32/esp
 3713     # setup
 3714     (clear-stream _test-input-stream)
 3715     (clear-stream $_test-input-buffered-file->buffer)
 3716     (clear-stream _test-output-stream)
 3717     (clear-stream $_test-output-buffered-file->buffer)
 3718     #
 3719     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3720     (write _test-input-stream "  x: int\n")
 3721     (write _test-input-stream "  y: int\n")
 3722     (write _test-input-stream "  z: int\n")
 3723     (write _test-input-stream "}\n")
 3724     (write _test-input-stream "fn foo {\n")
 3725     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3726     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 3727     (write _test-input-stream "}\n")
 3728     # convert
 3729     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3730     (flush _test-output-buffered-file)
 3731 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3737     # check output
 3738     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 3739     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 3740     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 3741     (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")
 3742     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 3743     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 3744     # var arr
 3745     (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")
 3746     (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")
 3747     # length instruction
 3748     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 3749     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 3750     (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")
 3751     (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")
 3752     (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")
 3753     (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")
 3754     (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")
 3755     (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")
 3756     # reclaim arr
 3757     (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")
 3758     #
 3759     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 3760     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 3761     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 3762     (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")
 3763     (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")
 3764     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 3765     # . epilogue
 3766     89/<- %esp 5/r32/ebp
 3767     5d/pop-to-ebp
 3768     c3/return
 3769 
 3770 test-convert-length-of-array-of-user-defined-types-to-ecx:
 3771     # . prologue
 3772     55/push-ebp
 3773     89/<- %ebp 4/r32/esp
 3774     # setup
 3775     (clear-stream _test-input-stream)
 3776     (clear-stream $_test-input-buffered-file->buffer)
 3777     (clear-stream _test-output-stream)
 3778     (clear-stream $_test-output-buffered-file->buffer)
 3779     #
 3780     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3781     (write _test-input-stream "  x: int\n")
 3782     (write _test-input-stream "  y: int\n")
 3783     (write _test-input-stream "  z: int\n")
 3784     (write _test-input-stream "}\n")
 3785     (write _test-input-stream "fn foo {\n")
 3786     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3787     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 3788     (write _test-input-stream "}\n")
 3789     # convert
 3790     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3791     (flush _test-output-buffered-file)
 3792 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3798     # check output
 3799     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 3800     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 3801     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 3802     (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")
 3803     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 3804     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 3805     # var a
 3806     (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")
 3807     (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")
 3808     # var x
 3809     (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")
 3810     # length instruction
 3811     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 3812     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 3813     (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")
 3814     (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")
 3815     (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")
 3816     (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")
 3817     (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")
 3818     (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")
 3819     (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")
 3820     # reclaim x
 3821     (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")
 3822     # reclaim a
 3823     (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")
 3824     #
 3825     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 3826     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 3827     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 3828     (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")
 3829     (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")
 3830     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 3831     # . epilogue
 3832     89/<- %esp 5/r32/ebp
 3833     5d/pop-to-ebp
 3834     c3/return
 3835 
 3836 test-convert-length-of-array-of-user-defined-types-to-edx:
 3837     # . prologue
 3838     55/push-ebp
 3839     89/<- %ebp 4/r32/esp
 3840     # setup
 3841     (clear-stream _test-input-stream)
 3842     (clear-stream $_test-input-buffered-file->buffer)
 3843     (clear-stream _test-output-stream)
 3844     (clear-stream $_test-output-buffered-file->buffer)
 3845     #
 3846     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 3847     (write _test-input-stream "  x: int\n")
 3848     (write _test-input-stream "  y: int\n")
 3849     (write _test-input-stream "  z: int\n")
 3850     (write _test-input-stream "}\n")
 3851     (write _test-input-stream "fn foo {\n")
 3852     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3853     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 3854     (write _test-input-stream "}\n")
 3855     # convert
 3856     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3857     (flush _test-output-buffered-file)
 3858 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3864     # check output
 3865     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 3866     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 3867     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 3868     (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")
 3869     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 3870     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 3871     # var a
 3872     (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")
 3873     (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")
 3874     # var x
 3875     (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")
 3876     # length instruction
 3877     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 3878     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 3879     (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")
 3880     (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")
 3881     (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")
 3882     (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")
 3883     (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")
 3884     (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")
 3885     (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")
 3886     # reclaim x
 3887     (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")
 3888     # reclaim a
 3889     (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")
 3890     #
 3891     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 3892     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 3893     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 3894     (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")
 3895     (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")
 3896     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 3897     # . epilogue
 3898     89/<- %esp 5/r32/ebp
 3899     5d/pop-to-ebp
 3900     c3/return
 3901 
 3902 test-convert-length-of-array-of-user-defined-types:
 3903     # . prologue
 3904     55/push-ebp
 3905     89/<- %ebp 4/r32/esp
 3906     # setup
 3907     (clear-stream _test-input-stream)
 3908     (clear-stream $_test-input-buffered-file->buffer)
 3909     (clear-stream _test-output-stream)
 3910     (clear-stream $_test-output-buffered-file->buffer)
 3911     #
 3912     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 3913     (write _test-input-stream "  x: int\n")
 3914     (write _test-input-stream "  y: int\n")
 3915     (write _test-input-stream "  z: int\n")
 3916     (write _test-input-stream "}\n")
 3917     (write _test-input-stream "fn foo {\n")
 3918     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 3919     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 3920     (write _test-input-stream "}\n")
 3921     # convert
 3922     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3923     (flush _test-output-buffered-file)
 3924 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3930     # check output
 3931     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 3932     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 3933     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 3934     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 3935     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 3936     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 3937     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 3938     (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")
 3939     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 3940     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 3941     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 3942     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 3943     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 3944     (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")
 3945     (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")
 3946     (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")
 3947     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 3948     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 3949     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 3950     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 3951     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 3952     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 3953     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 3954     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 3955     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 3956     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 3957     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 3958     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 3959     # . epilogue
 3960     89/<- %esp 5/r32/ebp
 3961     5d/pop-to-ebp
 3962     c3/return
 3963 
 3964 #######################################################
 3965 # Parsing
 3966 #######################################################
 3967 
 3968 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 3969     # pseudocode
 3970     #   var curr-function: (addr handle function) = Program->functions
 3971     #   var curr-type: (addr handle typeinfo) = Program->types
 3972     #   var line: (stream byte 512)
 3973     #   var word-slice: slice
 3974     #   while true                                  # line loop
 3975     #     clear-stream(line)
 3976     #     read-line-buffered(in, line)
 3977     #     if (line->write == 0) break               # end of file
 3978     #     word-slice = next-mu-token(line)
 3979     #     if slice-empty?(word-slice)               # end of line
 3980     #       continue
 3981     #     else if slice-starts-with?(word-slice, "#")  # comment
 3982     #       continue                                # end of line
 3983     #     else if slice-equal?(word-slice, "fn")
 3984     #       var new-function: (handle function) = allocate(function)
 3985     #       var vars: (stack live-var 256)
 3986     #       populate-mu-function-header(line, new-function, vars)
 3987     #       populate-mu-function-body(in, new-function, vars)
 3988     #       assert(vars->top == 0)
 3989     #       *curr-function = new-function
 3990     #       curr-function = &new-function->next
 3991     #     else if slice-equal?(word-slice, "type")
 3992     #       word-slice = next-mu-token(line)
 3993     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 3994     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 3995     #       assert(next-word(line) == "{")
 3996     #       populate-mu-type(in, new-type)
 3997     #     else
 3998     #       abort()
 3999     #
 4000     # . prologue
 4001     55/push-ebp
 4002     89/<- %ebp 4/r32/esp
 4003     # . save registers
 4004     50/push-eax
 4005     51/push-ecx
 4006     52/push-edx
 4007     53/push-ebx
 4008     56/push-esi
 4009     57/push-edi
 4010     # var line/ecx: (stream byte 512)
 4011     81 5/subop/subtract %esp 0x200/imm32
 4012     68/push 0x200/imm32/size
 4013     68/push 0/imm32/read
 4014     68/push 0/imm32/write
 4015     89/<- %ecx 4/r32/esp
 4016     # var word-slice/edx: slice
 4017     68/push 0/imm32/end
 4018     68/push 0/imm32/start
 4019     89/<- %edx 4/r32/esp
 4020     # var curr-function/edi: (addr handle function)
 4021     bf/copy-to-edi _Program-functions/imm32
 4022     # var vars/ebx: (stack live-var 256)
 4023     81 5/subop/subtract %esp 0xc00/imm32
 4024     68/push 0xc00/imm32/size
 4025     68/push 0/imm32/top
 4026     89/<- %ebx 4/r32/esp
 4027     {
 4028 $parse-mu:line-loop:
 4029       (clear-stream %ecx)
 4030       (read-line-buffered *(ebp+8) %ecx)
 4031       # if (line->write == 0) break
 4032       81 7/subop/compare *ecx 0/imm32
 4033       0f 84/jump-if-= break/disp32
 4034 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 4040       (next-mu-token %ecx %edx)
 4041       # if slice-empty?(word-slice) continue
 4042       (slice-empty? %edx)  # => eax
 4043       3d/compare-eax-and 0/imm32/false
 4044       0f 85/jump-if-!= loop/disp32
 4045       # if (*word-slice->start == "#") continue
 4046       # . eax = *word-slice->start
 4047       8b/-> *edx 0/r32/eax
 4048       8a/copy-byte *eax 0/r32/AL
 4049       81 4/subop/and %eax 0xff/imm32
 4050       # . if (eax == '#') continue
 4051       3d/compare-eax-and 0x23/imm32/hash
 4052       0f 84/jump-if-= loop/disp32
 4053       # if (slice-equal?(word-slice, "fn")) parse a function
 4054       {
 4055 $parse-mu:fn:
 4056         (slice-equal? %edx "fn")  # => eax
 4057         3d/compare-eax-and 0/imm32/false
 4058         0f 84/jump-if-= break/disp32
 4059         # var new-function/esi: (handle function)
 4060         68/push 0/imm32
 4061         68/push 0/imm32
 4062         89/<- %esi 4/r32/esp
 4063         # populate-mu-function(line, in, vars, new-function)
 4064         (allocate Heap *Function-size %esi)
 4065         # var new-function-addr/eax: (addr function)
 4066         (lookup *esi *(esi+4))  # => eax
 4067         (clear-stack %ebx)
 4068         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 4069         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 4070         # *curr-function = new-function
 4071         8b/-> *esi 0/r32/eax
 4072         89/<- *edi 0/r32/eax
 4073         8b/-> *(esi+4) 0/r32/eax
 4074         89/<- *(edi+4) 0/r32/eax
 4075         # curr-function = &new-function->next
 4076         # . var tmp/eax: (addr function) = lookup(new-function)
 4077         (lookup *esi *(esi+4))  # => eax
 4078         # . curr-function = &tmp->next
 4079         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 4080         # reclaim new-function
 4081         81 0/subop/add %esp 8/imm32
 4082         #
 4083         e9/jump $parse-mu:line-loop/disp32
 4084       }
 4085       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 4086       {
 4087 $parse-mu:type:
 4088         (slice-equal? %edx "type")  # => eax
 4089         3d/compare-eax-and 0/imm32
 4090         0f 84/jump-if-= break/disp32
 4091         (next-mu-token %ecx %edx)
 4092         # var type-id/eax: int
 4093         (pos-or-insert-slice Type-id %edx)  # => eax
 4094         # spill
 4095         51/push-ecx
 4096         # var new-type/ecx: (handle typeinfo)
 4097         68/push 0/imm32
 4098         68/push 0/imm32
 4099         89/<- %ecx 4/r32/esp
 4100         (find-or-create-typeinfo %eax %ecx)
 4101         #
 4102         (lookup *ecx *(ecx+4))  # => eax
 4103         # TODO: ensure that 'line' has nothing else but '{'
 4104 #? (dump-typeinfos "=== aaa\n")
 4105         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 4106 #? (dump-typeinfos "=== zzz\n")
 4107         # reclaim new-type
 4108         81 0/subop/add %esp 8/imm32
 4109         # restore
 4110         59/pop-to-ecx
 4111         e9/jump $parse-mu:line-loop/disp32
 4112       }
 4113       # otherwise abort
 4114       e9/jump $parse-mu:error1/disp32
 4115     } # end line loop
 4116 $parse-mu:end:
 4117     # . reclaim locals
 4118     81 0/subop/add %esp 0xe1c/imm32
 4119     # . restore registers
 4120     5f/pop-to-edi
 4121     5e/pop-to-esi
 4122     5b/pop-to-ebx
 4123     5a/pop-to-edx
 4124     59/pop-to-ecx
 4125     58/pop-to-eax
 4126     # . epilogue
 4127     89/<- %esp 5/r32/ebp
 4128     5d/pop-to-ebp
 4129     c3/return
 4130 
 4131 $parse-mu:error1:
 4132     # error("unexpected top-level command: " word-slice "\n")
 4133     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 4134     (write-slice-buffered *(ebp+0xc) %edx)
 4135     (write-buffered *(ebp+0xc) "\n")
 4136     (flush *(ebp+0xc))
 4137     (stop *(ebp+0x10) 1)
 4138     # never gets here
 4139 
 4140 $parse-mu:error2:
 4141     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 4142     (print-int32-buffered *(ebp+0xc) *ebx)
 4143     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 4144     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 4145     (write-buffered *(ebp+0xc) "'\n")
 4146     (flush *(ebp+0xc))
 4147     (stop *(ebp+0x10) 1)
 4148     # never gets here
 4149 
 4150 # scenarios considered:
 4151 # ✗ fn foo  # no block
 4152 # ✓ fn foo {
 4153 # ✗ fn foo { {
 4154 # ✗ fn foo { }
 4155 # ✗ fn foo { } {
 4156 # ✗ fn foo x {
 4157 # ✗ fn foo x: {
 4158 # ✓ fn foo x: int {
 4159 # ✓ fn foo x: int {
 4160 # ✓ fn foo x: int -> y/eax: int {
 4161 populate-mu-function-header:  # first-line: (addr stream byte), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 4162     # pseudocode:
 4163     #   var name: slice
 4164     #   next-mu-token(first-line, name)
 4165     #   assert(name not in '{' '}' '->')
 4166     #   out->name = slice-to-string(name)
 4167     #   ## inouts
 4168     #   while true
 4169     #     ## name
 4170     #     name = next-mu-token(first-line)
 4171     #     if (name == '{') goto done
 4172     #     if (name == '->') break
 4173     #     assert(name != '}')
 4174     #     var v: (handle var) = parse-var-with-type(name, first-line)
 4175     #     assert(v->register == null)
 4176     #     # v->block-depth is implicitly 0
 4177     #     out->inouts = append(v, out->inouts)
 4178     #     push(vars, {v, false})
 4179     #   ## outputs
 4180     #   while true
 4181     #     ## name
 4182     #     name = next-mu-token(first-line)
 4183     #     assert(name not in '{' '}' '->')
 4184     #     var v: (handle var) = parse-var-with-type(name, first-line)
 4185     #     assert(v->register != null)
 4186     #     out->outputs = append(v, out->outputs)
 4187     #   done:
 4188     #
 4189     # . prologue
 4190     55/push-ebp
 4191     89/<- %ebp 4/r32/esp
 4192     # . save registers
 4193     50/push-eax
 4194     51/push-ecx
 4195     52/push-edx
 4196     53/push-ebx
 4197     57/push-edi
 4198     # edi = out
 4199     8b/-> *(ebp+0xc) 7/r32/edi
 4200     # var word-slice/ecx: slice
 4201     68/push 0/imm32/end
 4202     68/push 0/imm32/start
 4203     89/<- %ecx 4/r32/esp
 4204     # var v/ebx: (handle var)
 4205     68/push 0/imm32
 4206     68/push 0/imm32
 4207     89/<- %ebx 4/r32/esp
 4208     # read function name
 4209     (next-mu-token *(ebp+8) %ecx)
 4210     # error checking
 4211     # TODO: error if name starts with 'break' or 'loop'
 4212     # if (word-slice == '{') abort
 4213     (slice-equal? %ecx "{")   # => eax
 4214     3d/compare-eax-and 0/imm32/false
 4215     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4216     # if (word-slice == '->') abort
 4217     (slice-equal? %ecx "->")   # => eax
 4218     3d/compare-eax-and 0/imm32/false
 4219     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4220     # if (word-slice == '}') abort
 4221     (slice-equal? %ecx "}")   # => eax
 4222     3d/compare-eax-and 0/imm32/false
 4223     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4224     # save function name
 4225     (slice-to-string Heap %ecx %edi)  # Function-name
 4226     # save function inouts
 4227     {
 4228 $populate-mu-function-header:check-for-inout:
 4229       (next-mu-token *(ebp+8) %ecx)
 4230       # if (word-slice == '{') goto done
 4231       (slice-equal? %ecx "{")   # => eax
 4232       3d/compare-eax-and 0/imm32/false
 4233       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 4234       # if (word-slice == '->') break
 4235       (slice-equal? %ecx "->")   # => eax
 4236       3d/compare-eax-and 0/imm32/false
 4237       0f 85/jump-if-!= break/disp32
 4238       # if (word-slice == '}') abort
 4239       (slice-equal? %ecx "}")   # => eax
 4240       3d/compare-eax-and 0/imm32/false
 4241       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4242       # v = parse-var-with-type(word-slice, first-line)
 4243       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 4244       # assert(v->register == null)
 4245       # . eax: (addr var) = lookup(v)
 4246       (lookup *ebx *(ebx+4))  # => eax
 4247       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 4248       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 4249       # v->block-depth is implicitly 0
 4250       #
 4251       # out->inouts = append(v, out->inouts)
 4252       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 4253       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 4254       # push(vars, {v, false})
 4255       (push *(ebp+0x10) *ebx)
 4256       (push *(ebp+0x10) *(ebx+4))
 4257       (push *(ebp+0x10) 0)  # false
 4258       #
 4259       e9/jump loop/disp32
 4260     }
 4261     # save function outputs
 4262     {
 4263 $populate-mu-function-header:check-for-out:
 4264       (next-mu-token *(ebp+8) %ecx)
 4265       # if (word-slice == '{') break
 4266       (slice-equal? %ecx "{")   # => eax
 4267       3d/compare-eax-and 0/imm32/false
 4268       0f 85/jump-if-!= break/disp32
 4269       # if (word-slice == '->') abort
 4270       (slice-equal? %ecx "->")   # => eax
 4271       3d/compare-eax-and 0/imm32/false
 4272       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4273       # if (word-slice == '}') abort
 4274       (slice-equal? %ecx "}")   # => eax
 4275       3d/compare-eax-and 0/imm32/false
 4276       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 4277       # v = parse-var-with-type(word-slice, first-line)
 4278       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 4279       # assert(var->register != null)
 4280       # . eax: (addr var) = lookup(v)
 4281       (lookup *ebx *(ebx+4))  # => eax
 4282       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 4283       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 4284       # out->outputs = append(v, out->outputs)
 4285       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 4286       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 4287       #
 4288       e9/jump loop/disp32
 4289     }
 4290 $populate-mu-function-header:done:
 4291     (check-no-tokens-left *(ebp+8))
 4292 $populate-mu-function-header:end:
 4293     # . reclaim locals
 4294     81 0/subop/add %esp 0x10/imm32
 4295     # . restore registers
 4296     5f/pop-to-edi
 4297     5b/pop-to-ebx
 4298     5a/pop-to-edx
 4299     59/pop-to-ecx
 4300     58/pop-to-eax
 4301     # . epilogue
 4302     89/<- %esp 5/r32/ebp
 4303     5d/pop-to-ebp
 4304     c3/return
 4305 
 4306 $populate-mu-function-header:error1:
 4307     # error("function header not in form 'fn <name> {'")
 4308     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 4309     (flush *(ebp+0x14))
 4310     (rewind-stream *(ebp+8))
 4311     (write-stream 2 *(ebp+8))
 4312     (write-buffered *(ebp+0x14) "'\n")
 4313     (flush *(ebp+0x14))
 4314     (stop *(ebp+0x18) 1)
 4315     # never gets here
 4316 
 4317 $populate-mu-function-header:error2:
 4318     # error("function input '" var "' cannot be in a register")
 4319     (write-buffered *(ebp+0x14) "function input '")
 4320     (write-buffered *(ebp+0x14) *ebx)  # Var-name
 4321     (write-buffered *(ebp+0x14) "' cannot be in a register")
 4322     (flush *(ebp+0x14))
 4323     (stop *(ebp+0x18) 1)
 4324     # never gets here
 4325 
 4326 $populate-mu-function-header:error3:
 4327     # error("function input '" var "' must be in a register")
 4328     (write-buffered *(ebp+0x14) "function input '")
 4329     (lookup *ebx *(ebx+4))  # => eax
 4330     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 4331     (write-buffered *(ebp+0x14) %eax)
 4332     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 4333     (flush *(ebp+0x14))
 4334     (rewind-stream *(ebp+8))
 4335     (write-stream 2 *(ebp+8))
 4336     (write-buffered *(ebp+0x14) "'\n")
 4337     (flush *(ebp+0x14))
 4338     (stop *(ebp+0x18) 1)
 4339     # never gets here
 4340 
 4341 test-function-header-with-arg:
 4342     # . prologue
 4343     55/push-ebp
 4344     89/<- %ebp 4/r32/esp
 4345     # setup
 4346     (clear-stream _test-input-stream)
 4347     (write _test-input-stream "foo n: int {\n")
 4348     # var result/ecx: function
 4349     2b/subtract *Function-size 4/r32/esp
 4350     89/<- %ecx 4/r32/esp
 4351     (zero-out %ecx *Function-size)
 4352     # var vars/ebx: (stack live-var 16)
 4353     81 5/subop/subtract %esp 0xc0/imm32
 4354     68/push 0xc0/imm32/size
 4355     68/push 0/imm32/top
 4356     89/<- %ebx 4/r32/esp
 4357     # convert
 4358     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 4359     # check result->name
 4360     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4361     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 4362     # var v/edx: (addr var) = result->inouts->value
 4363     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4364     (lookup *eax *(eax+4))  # List-value List-value => eax
 4365     89/<- %edx 0/r32/eax
 4366     # check v->name
 4367     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 4368     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 4369     # check v->type
 4370     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 4371     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Tree-is-atom
 4372     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Tree-value
 4373     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Tree-right
 4374     # . epilogue
 4375     89/<- %esp 5/r32/ebp
 4376     5d/pop-to-ebp
 4377     c3/return
 4378 
 4379 test-function-header-with-multiple-args:
 4380     # . prologue
 4381     55/push-ebp
 4382     89/<- %ebp 4/r32/esp
 4383     # setup
 4384     (clear-stream _test-input-stream)
 4385     (write _test-input-stream "foo a: int, b: int c: int {\n")
 4386     # result/ecx: function
 4387     2b/subtract *Function-size 4/r32/esp
 4388     89/<- %ecx 4/r32/esp
 4389     (zero-out %ecx *Function-size)
 4390     # var vars/ebx: (stack live-var 16)
 4391     81 5/subop/subtract %esp 0xc0/imm32
 4392     68/push 0xc0/imm32/size
 4393     68/push 0/imm32/top
 4394     89/<- %ebx 4/r32/esp
 4395     # convert
 4396     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 4397     # check result->name
 4398     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4399     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 4400     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4401     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4402     89/<- %edx 0/r32/eax
 4403 $test-function-header-with-multiple-args:inout0:
 4404     # var v/ebx: (addr var) = lookup(inouts->value)
 4405     (lookup *edx *(edx+4))  # List-value List-value => eax
 4406     89/<- %ebx 0/r32/eax
 4407     # check v->name
 4408     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4409     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 4410     # check v->type
 4411     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4412     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Tree-is-atom
 4413     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Tree-value
 4414     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Tree-right
 4415 $test-function-header-with-multiple-args:inout1:
 4416     # inouts = lookup(inouts->next)
 4417     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4418     89/<- %edx 0/r32/eax
 4419     # v = lookup(inouts->value)
 4420     (lookup *edx *(edx+4))  # List-value List-value => eax
 4421     89/<- %ebx 0/r32/eax
 4422     # check v->name
 4423     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4424     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 4425     # check v->type
 4426     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4427     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Tree-is-atom
 4428     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Tree-value
 4429     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Tree-right
 4430 $test-function-header-with-multiple-args:inout2:
 4431     # inouts = lookup(inouts->next)
 4432     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4433     89/<- %edx 0/r32/eax
 4434     # v = lookup(inouts->value)
 4435     (lookup *edx *(edx+4))  # List-value List-value => eax
 4436     89/<- %ebx 0/r32/eax
 4437     # check v->name
 4438     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4439     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 4440     # check v->type
 4441     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4442     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Tree-is-atom
 4443     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Tree-value
 4444     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Tree-right
 4445     # . epilogue
 4446     89/<- %esp 5/r32/ebp
 4447     5d/pop-to-ebp
 4448     c3/return
 4449 
 4450 test-function-header-with-multiple-args-and-outputs:
 4451     # . prologue
 4452     55/push-ebp
 4453     89/<- %ebp 4/r32/esp
 4454     # setup
 4455     (clear-stream _test-input-stream)
 4456     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 4457     # result/ecx: function
 4458     2b/subtract *Function-size 4/r32/esp
 4459     89/<- %ecx 4/r32/esp
 4460     (zero-out %ecx *Function-size)
 4461     # var vars/ebx: (stack live-var 16)
 4462     81 5/subop/subtract %esp 0xc0/imm32
 4463     68/push 0xc0/imm32/size
 4464     68/push 0/imm32/top
 4465     89/<- %ebx 4/r32/esp
 4466     # convert
 4467     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 4468     # check result->name
 4469     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 4470     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 4471     # var inouts/edx: (addr list var) = lookup(result->inouts)
 4472     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 4473     89/<- %edx 0/r32/eax
 4474 $test-function-header-with-multiple-args-and-outputs:inout0:
 4475     # var v/ebx: (addr var) = lookup(inouts->value)
 4476     (lookup *edx *(edx+4))  # List-value List-value => eax
 4477     89/<- %ebx 0/r32/eax
 4478     # check v->name
 4479     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4480     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 4481     # check v->type
 4482     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4483     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Tree-is-atom
 4484     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Tree-value
 4485     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Tree-right
 4486 $test-function-header-with-multiple-args-and-outputs:inout1:
 4487     # inouts = lookup(inouts->next)
 4488     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4489     89/<- %edx 0/r32/eax
 4490     # v = lookup(inouts->value)
 4491     (lookup *edx *(edx+4))  # List-value List-value => eax
 4492     89/<- %ebx 0/r32/eax
 4493     # check v->name
 4494     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4495     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 4496     # check v->type
 4497     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4498     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Tree-is-atom
 4499     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Tree-value
 4500     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Tree-right
 4501 $test-function-header-with-multiple-args-and-outputs:inout2:
 4502     # inouts = lookup(inouts->next)
 4503     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4504     89/<- %edx 0/r32/eax
 4505     # v = lookup(inouts->value)
 4506     (lookup *edx *(edx+4))  # List-value List-value => eax
 4507     89/<- %ebx 0/r32/eax
 4508     # check v->name
 4509     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4510     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 4511     # check v->type
 4512     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4513     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Tree-is-atom
 4514     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Tree-value
 4515     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Tree-right
 4516 $test-function-header-with-multiple-args-and-outputs:out0:
 4517     # var outputs/edx: (addr list var) = lookup(result->outputs)
 4518     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 4519     89/<- %edx 0/r32/eax
 4520     # v = lookup(outputs->value)
 4521     (lookup *edx *(edx+4))  # List-value List-value => eax
 4522     89/<- %ebx 0/r32/eax
 4523     # check v->name
 4524     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4525     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 4526     # check v->register
 4527     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4528     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 4529     # check v->type
 4530     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4531     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Tree-is-atom
 4532     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Tree-value
 4533     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Tree-right
 4534 $test-function-header-with-multiple-args-and-outputs:out1:
 4535     # outputs = lookup(outputs->next)
 4536     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 4537     89/<- %edx 0/r32/eax
 4538     # v = lookup(inouts->value)
 4539     (lookup *edx *(edx+4))  # List-value List-value => eax
 4540     89/<- %ebx 0/r32/eax
 4541     # check v->name
 4542     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 4543     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 4544     # check v->register
 4545     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 4546     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 4547     # check v->type
 4548     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 4549     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Tree-is-atom
 4550     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Tree-value
 4551     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Tree-right
 4552     # . epilogue
 4553     89/<- %esp 5/r32/ebp
 4554     5d/pop-to-ebp
 4555     c3/return
 4556 
 4557 # format for variables with types
 4558 #   x: int
 4559 #   x: int,
 4560 #   x/eax: int
 4561 #   x/eax: int,
 4562 # ignores at most one trailing comma
 4563 # WARNING: modifies name
 4564 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 4565     # pseudocode:
 4566     #   var s: slice
 4567     #   if (!slice-ends-with(name, ":"))
 4568     #     abort
 4569     #   --name->end to skip ':'
 4570     #   next-token-from-slice(name->start, name->end, '/', s)
 4571     #   new-var-from-slice(s, out)
 4572     #   ## register
 4573     #   next-token-from-slice(s->end, name->end, '/', s)
 4574     #   if (!slice-empty?(s))
 4575     #     out->register = slice-to-string(s)
 4576     #   ## type
 4577     #   var type: (handle tree type-id) = parse-type(first-line)
 4578     #   out->type = type
 4579     #
 4580     # . prologue
 4581     55/push-ebp
 4582     89/<- %ebp 4/r32/esp
 4583     # . save registers
 4584     50/push-eax
 4585     51/push-ecx
 4586     52/push-edx
 4587     53/push-ebx
 4588     56/push-esi
 4589     57/push-edi
 4590     # esi = name
 4591     8b/-> *(ebp+8) 6/r32/esi
 4592     # if (!slice-ends-with?(name, ":")) abort
 4593     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 4594     49/decrement-ecx
 4595     8a/copy-byte *ecx 1/r32/CL
 4596     81 4/subop/and %ecx 0xff/imm32
 4597     81 7/subop/compare %ecx 0x3a/imm32/colon
 4598     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 4599     # --name->end to skip ':'
 4600     ff 1/subop/decrement *(esi+4)
 4601     # var s/ecx: slice
 4602     68/push 0/imm32/end
 4603     68/push 0/imm32/start
 4604     89/<- %ecx 4/r32/esp
 4605 $parse-var-with-type:parse-name:
 4606     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 4607 $parse-var-with-type:create-var:
 4608     # new-var-from-slice(s, out)
 4609     (new-var-from-slice Heap %ecx *(ebp+0x10))
 4610     # save out->register
 4611 $parse-var-with-type:save-register:
 4612     # . var out-addr/edi: (addr var) = lookup(*out)
 4613     8b/-> *(ebp+0x10) 7/r32/edi
 4614     (lookup *edi *(edi+4))  # => eax
 4615     89/<- %edi 0/r32/eax
 4616     # . s = next-token(...)
 4617     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 4618     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 4619     {
 4620 $parse-var-with-type:write-register:
 4621       (slice-empty? %ecx)  # => eax
 4622       3d/compare-eax-and 0/imm32/false
 4623       75/jump-if-!= break/disp8
 4624       # out->register = slice-to-string(s)
 4625       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 4626       (slice-to-string Heap %ecx %eax)
 4627     }
 4628 $parse-var-with-type:save-type:
 4629     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 4630     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 4631 $parse-var-with-type:end:
 4632     # . reclaim locals
 4633     81 0/subop/add %esp 8/imm32
 4634     # . restore registers
 4635     5f/pop-to-edi
 4636     5e/pop-to-esi
 4637     5b/pop-to-ebx
 4638     5a/pop-to-edx
 4639     59/pop-to-ecx
 4640     58/pop-to-eax
 4641     # . epilogue
 4642     89/<- %esp 5/r32/ebp
 4643     5d/pop-to-ebp
 4644     c3/return
 4645 
 4646 $parse-var-with-type:abort:
 4647     # error("var should have form 'name: type' in '" line "'\n")
 4648     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 4649     (flush *(ebp+0x14))
 4650     (rewind-stream *(ebp+0xc))
 4651     (write-stream 2 *(ebp+0xc))
 4652     (write-buffered *(ebp+0x14) "'\n")
 4653     (flush *(ebp+0x14))
 4654     (stop *(ebp+0x18) 1)
 4655     # never gets here
 4656 
 4657 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 4658     # pseudocode:
 4659     #   var s: slice = next-mu-token(in)
 4660     #   assert s != ""
 4661     #   assert s != "->"
 4662     #   assert s != "{"
 4663     #   assert s != "}"
 4664     #   if s == ")"
 4665     #     return
 4666     #   out = allocate(Tree)
 4667     #   if s != "("
 4668     #     HACK: if s is an int, parse and return it
 4669     #     out->left-is-atom? = true
 4670     #     out->value = pos-or-insert-slice(Type-id, s)
 4671     #     return
 4672     #   out->left = parse-type(ad, in)
 4673     #   out->right = parse-type-tree(ad, in)
 4674     #
 4675     # . prologue
 4676     55/push-ebp
 4677     89/<- %ebp 4/r32/esp
 4678     # . save registers
 4679     50/push-eax
 4680     51/push-ecx
 4681     52/push-edx
 4682     # clear out
 4683     (zero-out *(ebp+0x10) *Handle-size)
 4684     # var s/ecx: slice
 4685     68/push 0/imm32
 4686     68/push 0/imm32
 4687     89/<- %ecx 4/r32/esp
 4688     # s = next-mu-token(in)
 4689     (next-mu-token *(ebp+0xc) %ecx)
 4690 #?     (write-buffered Stderr "tok: ")
 4691 #?     (write-slice-buffered Stderr %ecx)
 4692 #?     (write-buffered Stderr "$\n")
 4693 #?     (flush Stderr)
 4694     # assert s != ""
 4695     (slice-equal? %ecx "")  # => eax
 4696     3d/compare-eax-and 0/imm32/false
 4697     0f 85/jump-if-!= $parse-type:abort/disp32
 4698     # assert s != "{"
 4699     (slice-equal? %ecx "{")  # => eax
 4700     3d/compare-eax-and 0/imm32/false
 4701     0f 85/jump-if-!= $parse-type:abort/disp32
 4702     # assert s != "}"
 4703     (slice-equal? %ecx "}")  # => eax
 4704     3d/compare-eax-and 0/imm32/false
 4705     0f 85/jump-if-!= $parse-type:abort/disp32
 4706     # assert s != "->"
 4707     (slice-equal? %ecx "->")  # => eax
 4708     3d/compare-eax-and 0/imm32/false
 4709     0f 85/jump-if-!= $parse-type:abort/disp32
 4710     # if (s == ")") return
 4711     (slice-equal? %ecx ")")  # => eax
 4712     3d/compare-eax-and 0/imm32/false
 4713     0f 85/jump-if-!= $parse-type:end/disp32
 4714     # out = new tree
 4715     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4716     # var out-addr/edx: (addr tree type-id) = lookup(*out)
 4717     8b/-> *(ebp+0x10) 2/r32/edx
 4718     (lookup *edx *(edx+4))  # => eax
 4719     89/<- %edx 0/r32/eax
 4720     {
 4721       # if (s != "(") break
 4722       (slice-equal? %ecx "(")  # => eax
 4723       3d/compare-eax-and 0/imm32/false
 4724       75/jump-if-!= break/disp8
 4725       # EGREGIOUS HACK for static array sizes: if s is a number, parse it
 4726       {
 4727 $parse-type:check-for-int:
 4728         (is-hex-int? %ecx)  # => eax
 4729         3d/compare-eax-and 0/imm32/false
 4730         74/jump-if-= break/disp8
 4731 $parse-type:int:
 4732         (parse-hex-int-from-slice %ecx)  # => eax
 4733         89/<- *(edx+4) 0/r32/eax  # Tree-value
 4734         e9/jump $parse-type:end/disp32
 4735       }
 4736 $parse-type:atom:
 4737       # out->left-is-atom? = true
 4738       c7 0/subop/copy *edx 1/imm32/true  # Tree-is-atom
 4739       # out->value = pos-or-insert-slice(Type-id, s)
 4740       (pos-or-insert-slice Type-id %ecx)  # => eax
 4741       89/<- *(edx+4) 0/r32/eax  # Tree-value
 4742       e9/jump $parse-type:end/disp32
 4743     }
 4744 $parse-type:non-atom:
 4745     # otherwise s == "("
 4746     # out->left = parse-type(ad, in)
 4747     8d/copy-address *(edx+4) 0/r32/eax  # Tree-left
 4748     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 4749     # out->right = parse-type-tree(ad, in)
 4750     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4751     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 4752 $parse-type:end:
 4753     # . reclaim locals
 4754     81 0/subop/add %esp 8/imm32
 4755     # . restore registers
 4756     5a/pop-to-edx
 4757     59/pop-to-ecx
 4758     58/pop-to-eax
 4759     # . epilogue
 4760     89/<- %esp 5/r32/ebp
 4761     5d/pop-to-ebp
 4762     c3/return
 4763 
 4764 $parse-type:abort:
 4765     # error("unexpected token when parsing type: '" s "'\n")
 4766     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 4767     (write-slice-buffered *(ebp+0x14) %ecx)
 4768     (write-buffered *(ebp+0x14) "'\n")
 4769     (flush *(ebp+0x14))
 4770     (stop *(ebp+0x18) 1)
 4771     # never gets here
 4772 
 4773 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle tree type-id), err: (addr buffered-file), ed: (addr exit-descriptor)
 4774     # pseudocode:
 4775     #   var tmp: (handle tree type-id) = parse-type(ad, in)
 4776     #   if tmp == 0
 4777     #     return 0
 4778     #   out = allocate(Tree)
 4779     #   out->left = tmp
 4780     #   out->right = parse-type-tree(ad, in)
 4781     #
 4782     # . prologue
 4783     55/push-ebp
 4784     89/<- %ebp 4/r32/esp
 4785     # . save registers
 4786     50/push-eax
 4787     51/push-ecx
 4788     52/push-edx
 4789     #
 4790     (zero-out *(ebp+0x10) *Handle-size)
 4791     # var tmp/ecx: (handle tree type-id)
 4792     68/push 0/imm32
 4793     68/push 0/imm32
 4794     89/<- %ecx 4/r32/esp
 4795     # tmp = parse-type(ad, in)
 4796     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 4797     # if (tmp == 0) return
 4798     81 7/subop/compare *ecx 0/imm32
 4799     74/jump-if-= $parse-type-tree:end/disp8
 4800     # out = new tree
 4801     (allocate *(ebp+8) *Tree-size *(ebp+0x10))
 4802     # var out-addr/edx: (addr tree) = lookup(*out)
 4803     8b/-> *(ebp+0x10) 2/r32/edx
 4804     (lookup *edx *(edx+4))  # => eax
 4805     89/<- %edx 0/r32/eax
 4806     # out->left = tmp
 4807     8b/-> *ecx 0/r32/eax
 4808     89/<- *(edx+4) 0/r32/eax  # Tree-left
 4809     8b/-> *(ecx+4) 0/r32/eax
 4810     89/<- *(edx+8) 0/r32/eax  # Tree-left
 4811     # out->right = parse-type-tree(ad, in)
 4812     8d/copy-address *(edx+0xc) 0/r32/eax  # Tree-right
 4813     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 4814 $parse-type-tree:end:
 4815     # . reclaim locals
 4816     81 0/subop/add %esp 8/imm32
 4817     # . restore registers
 4818     5a/pop-to-edx
 4819     59/pop-to-ecx
 4820     58/pop-to-eax
 4821     # . epilogue
 4822     89/<- %esp 5/r32/ebp
 4823     5d/pop-to-ebp
 4824     c3/return
 4825 
 4826 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 4827     # pseudocode:
 4828     # start:
 4829     #   skip-chars-matching-whitespace(in)
 4830     #   if in->read >= in->write              # end of in
 4831     #     out = {0, 0}
 4832     #     return
 4833     #   out->start = &in->data[in->read]
 4834     #   var curr-byte/eax: byte = in->data[in->read]
 4835     #   if curr->byte == ','                  # comment token
 4836     #     ++in->read
 4837     #     goto start
 4838     #   if curr-byte == '#'                   # comment
 4839     #     goto done                             # treat as eof
 4840     #   if curr-byte == '"'                   # string literal
 4841     #     skip-string(in)
 4842     #     goto done                           # no metadata
 4843     #   if curr-byte == '('
 4844     #     ++in->read
 4845     #     goto done
 4846     #   if curr-byte == ')'
 4847     #     ++in->read
 4848     #     goto done
 4849     #   # read a word
 4850     #   while true
 4851     #     if in->read >= in->write
 4852     #       break
 4853     #     curr-byte = in->data[in->read]
 4854     #     if curr-byte == ' '
 4855     #       break
 4856     #     if curr-byte == '\r'
 4857     #       break
 4858     #     if curr-byte == '\n'
 4859     #       break
 4860     #     if curr-byte == '('
 4861     #       break
 4862     #     if curr-byte == ')'
 4863     #       break
 4864     #     if curr-byte == ','
 4865     #       break
 4866     #     ++in->read
 4867     # done:
 4868     #   out->end = &in->data[in->read]
 4869     #
 4870     # . prologue
 4871     55/push-ebp
 4872     89/<- %ebp 4/r32/esp
 4873     # . save registers
 4874     50/push-eax
 4875     51/push-ecx
 4876     56/push-esi
 4877     57/push-edi
 4878     # esi = in
 4879     8b/-> *(ebp+8) 6/r32/esi
 4880     # edi = out
 4881     8b/-> *(ebp+0xc) 7/r32/edi
 4882 $next-mu-token:start:
 4883     (skip-chars-matching-whitespace %esi)
 4884 $next-mu-token:check0:
 4885     # if (in->read >= in->write) return out = {0, 0}
 4886     # . ecx = in->read
 4887     8b/-> *(esi+4) 1/r32/ecx
 4888     # . if (ecx >= in->write) return out = {0, 0}
 4889     3b/compare<- *esi 1/r32/ecx
 4890     c7 0/subop/copy *edi 0/imm32
 4891     c7 0/subop/copy *(edi+4) 0/imm32
 4892     0f 8d/jump-if->= $next-mu-token:end/disp32
 4893     # out->start = &in->data[in->read]
 4894     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4895     89/<- *edi 0/r32/eax
 4896     # var curr-byte/eax: byte = in->data[in->read]
 4897     31/xor-with %eax 0/r32/eax
 4898     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4899     {
 4900 $next-mu-token:check-for-comma:
 4901       # if (curr-byte != ',') break
 4902       3d/compare-eax-and 0x2c/imm32/comma
 4903       75/jump-if-!= break/disp8
 4904       # ++in->read
 4905       ff 0/subop/increment *(esi+4)
 4906       # restart
 4907       e9/jump $next-mu-token:start/disp32
 4908     }
 4909     {
 4910 $next-mu-token:check-for-comment:
 4911       # if (curr-byte != '#') break
 4912       3d/compare-eax-and 0x23/imm32/pound
 4913       75/jump-if-!= break/disp8
 4914       # return eof
 4915       e9/jump $next-mu-token:done/disp32
 4916     }
 4917     {
 4918 $next-mu-token:check-for-string-literal:
 4919       # if (curr-byte != '"') break
 4920       3d/compare-eax-and 0x22/imm32/dquote
 4921       75/jump-if-!= break/disp8
 4922       (skip-string %esi)
 4923       # return
 4924       e9/jump $next-mu-token:done/disp32
 4925     }
 4926     {
 4927 $next-mu-token:check-for-open-paren:
 4928       # if (curr-byte != '(') break
 4929       3d/compare-eax-and 0x28/imm32/open-paren
 4930       75/jump-if-!= break/disp8
 4931       # ++in->read
 4932       ff 0/subop/increment *(esi+4)
 4933       # return
 4934       e9/jump $next-mu-token:done/disp32
 4935     }
 4936     {
 4937 $next-mu-token:check-for-close-paren:
 4938       # if (curr-byte != ')') break
 4939       3d/compare-eax-and 0x29/imm32/close-paren
 4940       75/jump-if-!= break/disp8
 4941       # ++in->read
 4942       ff 0/subop/increment *(esi+4)
 4943       # return
 4944       e9/jump $next-mu-token:done/disp32
 4945     }
 4946     {
 4947 $next-mu-token:regular-word-without-metadata:
 4948       # if (in->read >= in->write) break
 4949       # . ecx = in->read
 4950       8b/-> *(esi+4) 1/r32/ecx
 4951       # . if (ecx >= in->write) break
 4952       3b/compare<- *esi 1/r32/ecx
 4953       7d/jump-if->= break/disp8
 4954       # var c/eax: byte = in->data[in->read]
 4955       31/xor-with %eax 0/r32/eax
 4956       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 4957       # if (c == ' ') break
 4958       3d/compare-eax-and 0x20/imm32/space
 4959       74/jump-if-= break/disp8
 4960       # if (c == '\r') break
 4961       3d/compare-eax-and 0xd/imm32/carriage-return
 4962       74/jump-if-= break/disp8
 4963       # if (c == '\n') break
 4964       3d/compare-eax-and 0xa/imm32/newline
 4965       74/jump-if-= break/disp8
 4966       # if (c == '(') break
 4967       3d/compare-eax-and 0x28/imm32/open-paren
 4968       0f 84/jump-if-= break/disp32
 4969       # if (c == ')') break
 4970       3d/compare-eax-and 0x29/imm32/close-paren
 4971       0f 84/jump-if-= break/disp32
 4972       # if (c == ',') break
 4973       3d/compare-eax-and 0x2c/imm32/comma
 4974       0f 84/jump-if-= break/disp32
 4975       # ++in->read
 4976       ff 0/subop/increment *(esi+4)
 4977       #
 4978       e9/jump loop/disp32
 4979     }
 4980 $next-mu-token:done:
 4981     # out->end = &in->data[in->read]
 4982     8b/-> *(esi+4) 1/r32/ecx
 4983     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 4984     89/<- *(edi+4) 0/r32/eax
 4985 $next-mu-token:end:
 4986     # . restore registers
 4987     5f/pop-to-edi
 4988     5e/pop-to-esi
 4989     59/pop-to-ecx
 4990     58/pop-to-eax
 4991     # . epilogue
 4992     89/<- %esp 5/r32/ebp
 4993     5d/pop-to-ebp
 4994     c3/return
 4995 
 4996 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 4997     # . prologue
 4998     55/push-ebp
 4999     89/<- %ebp 4/r32/esp
 5000     # if (pos-slice(arr, s) != -1) return it
 5001     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 5002     3d/compare-eax-and -1/imm32
 5003     75/jump-if-!= $pos-or-insert-slice:end/disp8
 5004 $pos-or-insert-slice:insert:
 5005     # var s2/eax: (handle array byte)
 5006     68/push 0/imm32
 5007     68/push 0/imm32
 5008     89/<- %eax 4/r32/esp
 5009     (slice-to-string Heap *(ebp+0xc) %eax)
 5010     # throw away alloc-id
 5011     (lookup *eax *(eax+4))  # => eax
 5012     (write-int *(ebp+8) %eax)
 5013     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 5014 $pos-or-insert-slice:end:
 5015     # . reclaim locals
 5016     81 0/subop/add %esp 8/imm32
 5017     # . epilogue
 5018     89/<- %esp 5/r32/ebp
 5019     5d/pop-to-ebp
 5020     c3/return
 5021 
 5022 # return the index in an array of strings matching 's', -1 if not found
 5023 # index is denominated in elements, not bytes
 5024 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 5025     # . prologue
 5026     55/push-ebp
 5027     89/<- %ebp 4/r32/esp
 5028     # . save registers
 5029     51/push-ecx
 5030     52/push-edx
 5031     53/push-ebx
 5032     56/push-esi
 5033 #?     (write-buffered Stderr "pos-slice: ")
 5034 #?     (write-slice-buffered Stderr *(ebp+0xc))
 5035 #?     (write-buffered Stderr "\n")
 5036 #?     (flush Stderr)
 5037     # esi = arr
 5038     8b/-> *(ebp+8) 6/r32/esi
 5039     # var index/ecx: int = 0
 5040     b9/copy-to-ecx 0/imm32
 5041     # var curr/edx: (addr (addr array byte)) = arr->data
 5042     8d/copy-address *(esi+0xc) 2/r32/edx
 5043     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 5044     8b/-> *esi 3/r32/ebx
 5045     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 5046     {
 5047 #?       (write-buffered Stderr "  ")
 5048 #?       (print-int32-buffered Stderr %ecx)
 5049 #?       (write-buffered Stderr "\n")
 5050 #?       (flush Stderr)
 5051       # if (curr >= max) return -1
 5052       39/compare %edx 3/r32/ebx
 5053       b8/copy-to-eax -1/imm32
 5054       73/jump-if-addr>= $pos-slice:end/disp8
 5055       # if (slice-equal?(s, *curr)) break
 5056       (slice-equal? *(ebp+0xc) *edx)  # => eax
 5057       3d/compare-eax-and 0/imm32/false
 5058       75/jump-if-!= break/disp8
 5059       # ++index
 5060       41/increment-ecx
 5061       # curr += 4
 5062       81 0/subop/add %edx 4/imm32
 5063       #
 5064       eb/jump loop/disp8
 5065     }
 5066     # return index
 5067     89/<- %eax 1/r32/ecx
 5068 $pos-slice:end:
 5069 #?     (write-buffered Stderr "=> ")
 5070 #?     (print-int32-buffered Stderr %eax)
 5071 #?     (write-buffered Stderr "\n")
 5072     # . restore registers
 5073     5e/pop-to-esi
 5074     5b/pop-to-ebx
 5075     5a/pop-to-edx
 5076     59/pop-to-ecx
 5077     # . epilogue
 5078     89/<- %esp 5/r32/ebp
 5079     5d/pop-to-ebp
 5080     c3/return
 5081 
 5082 test-parse-var-with-type:
 5083     # . prologue
 5084     55/push-ebp
 5085     89/<- %ebp 4/r32/esp
 5086     # (eax..ecx) = "x:"
 5087     b8/copy-to-eax "x:"/imm32
 5088     8b/-> *eax 1/r32/ecx
 5089     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5090     05/add-to-eax 4/imm32
 5091     # var slice/ecx: slice = {eax, ecx}
 5092     51/push-ecx
 5093     50/push-eax
 5094     89/<- %ecx 4/r32/esp
 5095     # _test-input-stream contains "int"
 5096     (clear-stream _test-input-stream)
 5097     (write _test-input-stream "int")
 5098     # var v/edx: (handle var)
 5099     68/push 0/imm32
 5100     68/push 0/imm32
 5101     89/<- %edx 4/r32/esp
 5102     #
 5103     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5104     # var v-addr/edx: (addr var) = lookup(v)
 5105     (lookup *edx *(edx+4))  # => eax
 5106     89/<- %edx 0/r32/eax
 5107     # check v-addr->name
 5108     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5109     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 5110     # check v-addr->type
 5111     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5112     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Tree-is-atom
 5113     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Tree-value
 5114     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Tree-right
 5115     # . epilogue
 5116     89/<- %esp 5/r32/ebp
 5117     5d/pop-to-ebp
 5118     c3/return
 5119 
 5120 test-parse-var-with-type-and-register:
 5121     # . prologue
 5122     55/push-ebp
 5123     89/<- %ebp 4/r32/esp
 5124     # (eax..ecx) = "x/eax:"
 5125     b8/copy-to-eax "x/eax:"/imm32
 5126     8b/-> *eax 1/r32/ecx
 5127     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5128     05/add-to-eax 4/imm32
 5129     # var slice/ecx: slice = {eax, ecx}
 5130     51/push-ecx
 5131     50/push-eax
 5132     89/<- %ecx 4/r32/esp
 5133     # _test-input-stream contains "int"
 5134     (clear-stream _test-input-stream)
 5135     (write _test-input-stream "int")
 5136     # var v/edx: (handle var)
 5137     68/push 0/imm32
 5138     68/push 0/imm32
 5139     89/<- %edx 4/r32/esp
 5140     #
 5141     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5142     # var v-addr/edx: (addr var) = lookup(v)
 5143     (lookup *edx *(edx+4))  # => eax
 5144     89/<- %edx 0/r32/eax
 5145     # check v-addr->name
 5146     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5147     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 5148     # check v-addr->register
 5149     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 5150     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 5151     # check v-addr->type
 5152     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5153     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Tree-is-atom
 5154     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Tree-left
 5155     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Tree-right
 5156     # . epilogue
 5157     89/<- %esp 5/r32/ebp
 5158     5d/pop-to-ebp
 5159     c3/return
 5160 
 5161 test-parse-var-with-trailing-characters:
 5162     # . prologue
 5163     55/push-ebp
 5164     89/<- %ebp 4/r32/esp
 5165     # (eax..ecx) = "x:"
 5166     b8/copy-to-eax "x:"/imm32
 5167     8b/-> *eax 1/r32/ecx
 5168     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5169     05/add-to-eax 4/imm32
 5170     # var slice/ecx: slice = {eax, ecx}
 5171     51/push-ecx
 5172     50/push-eax
 5173     89/<- %ecx 4/r32/esp
 5174     # _test-input-stream contains "int,"
 5175     (clear-stream _test-input-stream)
 5176     (write _test-input-stream "int,")
 5177     # var v/edx: (handle var)
 5178     68/push 0/imm32
 5179     68/push 0/imm32
 5180     89/<- %edx 4/r32/esp
 5181     #
 5182     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5183     # var v-addr/edx: (addr var) = lookup(v)
 5184     (lookup *edx *(edx+4))  # => eax
 5185     89/<- %edx 0/r32/eax
 5186     # check v-addr->name
 5187     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5188     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 5189     # check v-addr->register
 5190     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 5191     # check v-addr->type
 5192     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5193     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Tree-is-atom
 5194     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-left
 5195     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Tree-right
 5196     # . epilogue
 5197     89/<- %esp 5/r32/ebp
 5198     5d/pop-to-ebp
 5199     c3/return
 5200 
 5201 test-parse-var-with-register-and-trailing-characters:
 5202     # . prologue
 5203     55/push-ebp
 5204     89/<- %ebp 4/r32/esp
 5205     # (eax..ecx) = "x/eax:"
 5206     b8/copy-to-eax "x/eax:"/imm32
 5207     8b/-> *eax 1/r32/ecx
 5208     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5209     05/add-to-eax 4/imm32
 5210     # var slice/ecx: slice = {eax, ecx}
 5211     51/push-ecx
 5212     50/push-eax
 5213     89/<- %ecx 4/r32/esp
 5214     # _test-input-stream contains "int,"
 5215     (clear-stream _test-input-stream)
 5216     (write _test-input-stream "int,")
 5217     # var v/edx: (handle var)
 5218     68/push 0/imm32
 5219     68/push 0/imm32
 5220     89/<- %edx 4/r32/esp
 5221     #
 5222     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5223     # var v-addr/edx: (addr var) = lookup(v)
 5224     (lookup *edx *(edx+4))  # => eax
 5225     89/<- %edx 0/r32/eax
 5226     # check v-addr->name
 5227     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5228     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 5229     # check v-addr->register
 5230     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 5231     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 5232     # check v-addr->type
 5233     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5234     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Tree-is-atom
 5235     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Tree-left
 5236     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Tree-right
 5237     # . epilogue
 5238     89/<- %esp 5/r32/ebp
 5239     5d/pop-to-ebp
 5240     c3/return
 5241 
 5242 test-parse-var-with-compound-type:
 5243     # . prologue
 5244     55/push-ebp
 5245     89/<- %ebp 4/r32/esp
 5246     # (eax..ecx) = "x:"
 5247     b8/copy-to-eax "x:"/imm32
 5248     8b/-> *eax 1/r32/ecx
 5249     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5250     05/add-to-eax 4/imm32
 5251     # var slice/ecx: slice = {eax, ecx}
 5252     51/push-ecx
 5253     50/push-eax
 5254     89/<- %ecx 4/r32/esp
 5255     # _test-input-stream contains "(addr int)"
 5256     (clear-stream _test-input-stream)
 5257     (write _test-input-stream "(addr int)")
 5258     # var v/edx: (handle var)
 5259     68/push 0/imm32
 5260     68/push 0/imm32
 5261     89/<- %edx 4/r32/esp
 5262     #
 5263     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 5264     # var v-addr/edx: (addr var) = lookup(v)
 5265     (lookup *edx *(edx+4))  # => eax
 5266     89/<- %edx 0/r32/eax
 5267     # check v-addr->name
 5268     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 5269     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 5270     # check v-addr->register
 5271     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 5272     # - check v-addr->type
 5273     # var type/edx: (addr tree type-id) = var->type
 5274     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 5275     89/<- %edx 0/r32/eax
 5276     # type is a non-atom
 5277     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Tree-is-atom
 5278     # type->left == atom(addr)
 5279     (lookup *(edx+4) *(edx+8))  # Tree-left Tree-left => eax
 5280     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Tree-is-atom
 5281     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Tree-value
 5282     # type->right->left == atom(int)
 5283     (lookup *(edx+0xc) *(edx+0x10))  # Tree-right Tree-right => eax
 5284     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 5285     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Tree-is-atom
 5286     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Tree-value
 5287     # type->right->right == null
 5288     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Tree-right
 5289     # . epilogue
 5290     89/<- %esp 5/r32/ebp
 5291     5d/pop-to-ebp
 5292     c3/return
 5293 
 5294 # identifier starts with a letter or '$' or '_'
 5295 # no constraints at the moment on later letters
 5296 # all we really want to do so far is exclude '{', '}' and '->'
 5297 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 5298     # . prologue
 5299     55/push-ebp
 5300     89/<- %ebp 4/r32/esp
 5301     # if (slice-empty?(in)) return false
 5302     (slice-empty? *(ebp+8))  # => eax
 5303     3d/compare-eax-and 0/imm32/false
 5304     75/jump-if-!= $is-identifier?:false/disp8
 5305     # var c/eax: byte = *in->start
 5306     8b/-> *(ebp+8) 0/r32/eax
 5307     8b/-> *eax 0/r32/eax
 5308     8a/copy-byte *eax 0/r32/AL
 5309     81 4/subop/and %eax 0xff/imm32
 5310     # if (c == '$') return true
 5311     3d/compare-eax-and 0x24/imm32/$
 5312     74/jump-if-= $is-identifier?:true/disp8
 5313     # if (c == '_') return true
 5314     3d/compare-eax-and 0x5f/imm32/_
 5315     74/jump-if-= $is-identifier?:true/disp8
 5316     # drop case
 5317     25/and-eax-with 0x5f/imm32
 5318     # if (c < 'A') return false
 5319     3d/compare-eax-and 0x41/imm32/A
 5320     7c/jump-if-< $is-identifier?:false/disp8
 5321     # if (c > 'Z') return false
 5322     3d/compare-eax-and 0x5a/imm32/Z
 5323     7f/jump-if-> $is-identifier?:false/disp8
 5324     # otherwise return true
 5325 $is-identifier?:true:
 5326     b8/copy-to-eax 1/imm32/true
 5327     eb/jump $is-identifier?:end/disp8
 5328 $is-identifier?:false:
 5329     b8/copy-to-eax 0/imm32/false
 5330 $is-identifier?:end:
 5331     # . epilogue
 5332     89/<- %esp 5/r32/ebp
 5333     5d/pop-to-ebp
 5334     c3/return
 5335 
 5336 test-is-identifier-dollar:
 5337     # . prologue
 5338     55/push-ebp
 5339     89/<- %ebp 4/r32/esp
 5340     # (eax..ecx) = "$a"
 5341     b8/copy-to-eax "$a"/imm32
 5342     8b/-> *eax 1/r32/ecx
 5343     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5344     05/add-to-eax 4/imm32
 5345     # var slice/ecx: slice = {eax, ecx}
 5346     51/push-ecx
 5347     50/push-eax
 5348     89/<- %ecx 4/r32/esp
 5349     #
 5350     (is-identifier? %ecx)
 5351     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 5352     # . epilogue
 5353     89/<- %esp 5/r32/ebp
 5354     5d/pop-to-ebp
 5355     c3/return
 5356 
 5357 test-is-identifier-underscore:
 5358     # . prologue
 5359     55/push-ebp
 5360     89/<- %ebp 4/r32/esp
 5361     # (eax..ecx) = "_a"
 5362     b8/copy-to-eax "_a"/imm32
 5363     8b/-> *eax 1/r32/ecx
 5364     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5365     05/add-to-eax 4/imm32
 5366     # var slice/ecx: slice = {eax, ecx}
 5367     51/push-ecx
 5368     50/push-eax
 5369     89/<- %ecx 4/r32/esp
 5370     #
 5371     (is-identifier? %ecx)
 5372     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 5373     # . epilogue
 5374     89/<- %esp 5/r32/ebp
 5375     5d/pop-to-ebp
 5376     c3/return
 5377 
 5378 test-is-identifier-a:
 5379     # . prologue
 5380     55/push-ebp
 5381     89/<- %ebp 4/r32/esp
 5382     # (eax..ecx) = "a$"
 5383     b8/copy-to-eax "a$"/imm32
 5384     8b/-> *eax 1/r32/ecx
 5385     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5386     05/add-to-eax 4/imm32
 5387     # var slice/ecx: slice = {eax, ecx}
 5388     51/push-ecx
 5389     50/push-eax
 5390     89/<- %ecx 4/r32/esp
 5391     #
 5392     (is-identifier? %ecx)
 5393     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 5394     # . epilogue
 5395     89/<- %esp 5/r32/ebp
 5396     5d/pop-to-ebp
 5397     c3/return
 5398 
 5399 test-is-identifier-z:
 5400     # . prologue
 5401     55/push-ebp
 5402     89/<- %ebp 4/r32/esp
 5403     # (eax..ecx) = "z$"
 5404     b8/copy-to-eax "z$"/imm32
 5405     8b/-> *eax 1/r32/ecx
 5406     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5407     05/add-to-eax 4/imm32
 5408     # var slice/ecx: slice = {eax, ecx}
 5409     51/push-ecx
 5410     50/push-eax
 5411     89/<- %ecx 4/r32/esp
 5412     #
 5413     (is-identifier? %ecx)
 5414     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 5415     # . epilogue
 5416     89/<- %esp 5/r32/ebp
 5417     5d/pop-to-ebp
 5418     c3/return
 5419 
 5420 test-is-identifier-A:
 5421     # . prologue
 5422     55/push-ebp
 5423     89/<- %ebp 4/r32/esp
 5424     # (eax..ecx) = "A$"
 5425     b8/copy-to-eax "A$"/imm32
 5426     8b/-> *eax 1/r32/ecx
 5427     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5428     05/add-to-eax 4/imm32
 5429     # var slice/ecx: slice = {eax, ecx}
 5430     51/push-ecx
 5431     50/push-eax
 5432     89/<- %ecx 4/r32/esp
 5433     #
 5434     (is-identifier? %ecx)
 5435     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 5436     # . epilogue
 5437     89/<- %esp 5/r32/ebp
 5438     5d/pop-to-ebp
 5439     c3/return
 5440 
 5441 test-is-identifier-Z:
 5442     # . prologue
 5443     55/push-ebp
 5444     89/<- %ebp 4/r32/esp
 5445     # (eax..ecx) = "Z$"
 5446     b8/copy-to-eax "Z$"/imm32
 5447     8b/-> *eax 1/r32/ecx
 5448     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5449     05/add-to-eax 4/imm32
 5450     # var slice/ecx: slice = {eax, ecx}
 5451     51/push-ecx
 5452     50/push-eax
 5453     89/<- %ecx 4/r32/esp
 5454     #
 5455     (is-identifier? %ecx)
 5456     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 5457     # . epilogue
 5458     89/<- %esp 5/r32/ebp
 5459     5d/pop-to-ebp
 5460     c3/return
 5461 
 5462 test-is-identifier-at:
 5463     # character before 'A' is invalid
 5464     # . prologue
 5465     55/push-ebp
 5466     89/<- %ebp 4/r32/esp
 5467     # (eax..ecx) = "@a"
 5468     b8/copy-to-eax "@a"/imm32
 5469     8b/-> *eax 1/r32/ecx
 5470     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5471     05/add-to-eax 4/imm32
 5472     # var slice/ecx: slice = {eax, ecx}
 5473     51/push-ecx
 5474     50/push-eax
 5475     89/<- %ecx 4/r32/esp
 5476     #
 5477     (is-identifier? %ecx)
 5478     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5479     # . epilogue
 5480     89/<- %esp 5/r32/ebp
 5481     5d/pop-to-ebp
 5482     c3/return
 5483 
 5484 test-is-identifier-square-bracket:
 5485     # character after 'Z' is invalid
 5486     # . prologue
 5487     55/push-ebp
 5488     89/<- %ebp 4/r32/esp
 5489     # (eax..ecx) = "[a"
 5490     b8/copy-to-eax "[a"/imm32
 5491     8b/-> *eax 1/r32/ecx
 5492     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5493     05/add-to-eax 4/imm32
 5494     # var slice/ecx: slice = {eax, ecx}
 5495     51/push-ecx
 5496     50/push-eax
 5497     89/<- %ecx 4/r32/esp
 5498     #
 5499     (is-identifier? %ecx)
 5500     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 5501     # . epilogue
 5502     89/<- %esp 5/r32/ebp
 5503     5d/pop-to-ebp
 5504     c3/return
 5505 
 5506 test-is-identifier-backtick:
 5507     # character before 'a' is invalid
 5508     # . prologue
 5509     55/push-ebp
 5510     89/<- %ebp 4/r32/esp
 5511     # (eax..ecx) = "`a"
 5512     b8/copy-to-eax "`a"/imm32
 5513     8b/-> *eax 1/r32/ecx
 5514     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5515     05/add-to-eax 4/imm32
 5516     # var slice/ecx: slice = {eax, ecx}
 5517     51/push-ecx
 5518     50/push-eax
 5519     89/<- %ecx 4/r32/esp
 5520     #
 5521     (is-identifier? %ecx)
 5522     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 5523     # . epilogue
 5524     89/<- %esp 5/r32/ebp
 5525     5d/pop-to-ebp
 5526     c3/return
 5527 
 5528 test-is-identifier-curly-brace-open:
 5529     # character after 'z' is invalid; also used for blocks
 5530     # . prologue
 5531     55/push-ebp
 5532     89/<- %ebp 4/r32/esp
 5533     # (eax..ecx) = "{a"
 5534     b8/copy-to-eax "{a"/imm32
 5535     8b/-> *eax 1/r32/ecx
 5536     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5537     05/add-to-eax 4/imm32
 5538     # var slice/ecx: slice = {eax, ecx}
 5539     51/push-ecx
 5540     50/push-eax
 5541     89/<- %ecx 4/r32/esp
 5542     #
 5543     (is-identifier? %ecx)
 5544     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 5545     # . epilogue
 5546     89/<- %esp 5/r32/ebp
 5547     5d/pop-to-ebp
 5548     c3/return
 5549 
 5550 test-is-identifier-curly-brace-close:
 5551     # . prologue
 5552     55/push-ebp
 5553     89/<- %ebp 4/r32/esp
 5554     # (eax..ecx) = "}a"
 5555     b8/copy-to-eax "}a"/imm32
 5556     8b/-> *eax 1/r32/ecx
 5557     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5558     05/add-to-eax 4/imm32
 5559     # var slice/ecx: slice = {eax, ecx}
 5560     51/push-ecx
 5561     50/push-eax
 5562     89/<- %ecx 4/r32/esp
 5563     #
 5564     (is-identifier? %ecx)
 5565     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 5566     # . epilogue
 5567     89/<- %esp 5/r32/ebp
 5568     5d/pop-to-ebp
 5569     c3/return
 5570 
 5571 test-is-identifier-hyphen:
 5572     # disallow leading '-' since '->' has special meaning
 5573     # . prologue
 5574     55/push-ebp
 5575     89/<- %ebp 4/r32/esp
 5576     # (eax..ecx) = "-a"
 5577     b8/copy-to-eax "-a"/imm32
 5578     8b/-> *eax 1/r32/ecx
 5579     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 5580     05/add-to-eax 4/imm32
 5581     # var slice/ecx: slice = {eax, ecx}
 5582     51/push-ecx
 5583     50/push-eax
 5584     89/<- %ecx 4/r32/esp
 5585     #
 5586     (is-identifier? %ecx)
 5587     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 5588     # . epilogue
 5589     89/<- %esp 5/r32/ebp
 5590     5d/pop-to-ebp
 5591     c3/return
 5592 
 5593 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 5594     # . prologue
 5595     55/push-ebp
 5596     89/<- %ebp 4/r32/esp
 5597     # . save registers
 5598     50/push-eax
 5599     56/push-esi
 5600     57/push-edi
 5601     # esi = in
 5602     8b/-> *(ebp+8) 6/r32/esi
 5603     # edi = out
 5604     8b/-> *(ebp+0xc) 7/r32/edi
 5605     # parse-mu-block(in, vars, out, out->body)
 5606     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 5607     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 5608 $populate-mu-function-body:end:
 5609     # . restore registers
 5610     5f/pop-to-edi
 5611     5e/pop-to-esi
 5612     58/pop-to-eax
 5613     # . epilogue
 5614     89/<- %esp 5/r32/ebp
 5615     5d/pop-to-ebp
 5616     c3/return
 5617 
 5618 # parses a block, assuming that the leading '{' has already been read by the caller
 5619 parse-mu-block:  # in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle block), err: (addr buffered-file), ed: (addr exit-descriptor)
 5620     # pseudocode:
 5621     #   var line: (stream byte 512)
 5622     #   var word-slice: slice
 5623     #   allocate(Heap, Stmt-size, out)
 5624     #   var out-addr: (addr block) = lookup(*out)
 5625     #   out-addr->tag = 0/block
 5626     #   out-addr->var = some unique name
 5627     #   push(vars, {out-addr->var, false})
 5628     #   while true                                  # line loop
 5629     #     clear-stream(line)
 5630     #     read-line-buffered(in, line)
 5631     #     if (line->write == 0) break               # end of file
 5632     #     word-slice = next-mu-token(line)
 5633     #     if slice-empty?(word-slice)               # end of line
 5634     #       continue
 5635     #     else if slice-starts-with?(word-slice, "#")
 5636     #       continue
 5637     #     else if slice-equal?(word-slice, "{")
 5638     #       assert(no-tokens-in(line))
 5639     #       block = parse-mu-block(in, vars, fn)
 5640     #       append-to-block(out-addr, block)
 5641     #     else if slice-equal?(word-slice, "}")
 5642     #       break
 5643     #     else if slice-ends-with?(word-slice, ":")
 5644     #       # TODO: error-check the rest of 'line'
 5645     #       --word-slice->end to skip ':'
 5646     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 5647     #       append-to-block(out-addr, named-block)
 5648     #     else if slice-equal?(word-slice, "var")
 5649     #       var-def = parse-mu-var-def(line, vars, fn)
 5650     #       append-to-block(out-addr, var-def)
 5651     #     else
 5652     #       stmt = parse-mu-stmt(line, vars, fn)
 5653     #       append-to-block(out-addr, stmt)
 5654     #   pop(vars)
 5655     #
 5656     # . prologue
 5657     55/push-ebp
 5658     89/<- %ebp 4/r32/esp
 5659     # . save registers
 5660     50/push-eax
 5661     51/push-ecx
 5662     52/push-edx
 5663     53/push-ebx
 5664     57/push-edi
 5665     # var line/ecx: (stream byte 512)
 5666     81 5/subop/subtract %esp 0x200/imm32
 5667     68/push 0x200/imm32/size
 5668     68/push 0/imm32/read
 5669     68/push 0/imm32/write
 5670     89/<- %ecx 4/r32/esp
 5671     # var word-slice/edx: slice
 5672     68/push 0/imm32/end
 5673     68/push 0/imm32/start
 5674     89/<- %edx 4/r32/esp
 5675     # allocate into out
 5676     (allocate Heap *Stmt-size *(ebp+0x14))
 5677     # var out-addr/edi: (addr block) = lookup(*out)
 5678     8b/-> *(ebp+0x14) 7/r32/edi
 5679     (lookup *edi *(edi+4))  # => eax
 5680     89/<- %edi 0/r32/eax
 5681     # out-addr->tag is 0 (block) by default
 5682     # set out-addr->var
 5683     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 5684     (new-block-name *(ebp+0x10) %eax)
 5685     # push(vars, out-addr->var)
 5686     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 5687     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 5688     (push *(ebp+0xc) 0)  # false
 5689     {
 5690 $parse-mu-block:line-loop:
 5691       # line = read-line-buffered(in)
 5692       (clear-stream %ecx)
 5693       (read-line-buffered *(ebp+8) %ecx)
 5694 #?       (write-buffered Stderr "line: ")
 5695 #?       (write-stream-data Stderr %ecx)
 5696 #?       (write-buffered Stderr Newline)
 5697 #?       (flush Stderr)
 5698       # if (line->write == 0) break
 5699       81 7/subop/compare *ecx 0/imm32
 5700       0f 84/jump-if-= break/disp32
 5701       # word-slice = next-mu-token(line)
 5702       (next-mu-token %ecx %edx)
 5703 #?       (write-buffered Stderr "word: ")
 5704 #?       (write-slice-buffered Stderr %edx)
 5705 #?       (write-buffered Stderr Newline)
 5706 #?       (flush Stderr)
 5707       # if slice-empty?(word-slice) continue
 5708       (slice-empty? %edx)
 5709       3d/compare-eax-and 0/imm32/false
 5710       0f 85/jump-if-!= loop/disp32
 5711       # if (slice-starts-with?(word-slice, '#') continue
 5712       # . eax = *word-slice->start
 5713       8b/-> *edx 0/r32/eax
 5714       8a/copy-byte *eax 0/r32/AL
 5715       81 4/subop/and %eax 0xff/imm32
 5716       # . if (eax == '#') continue
 5717       3d/compare-eax-and 0x23/imm32/hash
 5718       0f 84/jump-if-= loop/disp32
 5719       # if slice-equal?(word-slice, "{")
 5720       {
 5721 $parse-mu-block:check-for-block:
 5722         (slice-equal? %edx "{")
 5723         3d/compare-eax-and 0/imm32/false
 5724         74/jump-if-= break/disp8
 5725         (check-no-tokens-left %ecx)
 5726         # parse new block and append
 5727         # . var tmp/eax: (handle block)
 5728         68/push 0/imm32
 5729         68/push 0/imm32
 5730         89/<- %eax 4/r32/esp
 5731         # .
 5732         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 5733         (append-to-block Heap %edi  *eax *(eax+4))
 5734         # . reclaim tmp
 5735         81 0/subop/add %esp 8/imm32
 5736         # .
 5737         e9/jump $parse-mu-block:line-loop/disp32
 5738       }
 5739       # if slice-equal?(word-slice, "}") break
 5740 $parse-mu-block:check-for-end:
 5741       (slice-equal? %edx "}")
 5742       3d/compare-eax-and 0/imm32/false
 5743       0f 85/jump-if-!= break/disp32
 5744       # if slice-ends-with?(word-slice, ":") parse named block and append
 5745       {
 5746 $parse-mu-block:check-for-named-block:
 5747         # . eax = *(word-slice->end-1)
 5748         8b/-> *(edx+4) 0/r32/eax
 5749         48/decrement-eax
 5750         8a/copy-byte *eax 0/r32/AL
 5751         81 4/subop/and %eax 0xff/imm32
 5752         # . if (eax != ':') break
 5753         3d/compare-eax-and 0x3a/imm32/colon
 5754         0f 85/jump-if-!= break/disp32
 5755         # TODO: error-check the rest of 'line'
 5756         #
 5757         # skip ':'
 5758         ff 1/subop/decrement *(edx+4)  # Slice-end
 5759         # var tmp/eax: (handle block)
 5760         68/push 0/imm32
 5761         68/push 0/imm32
 5762         89/<- %eax 4/r32/esp
 5763         #
 5764         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax)
 5765         (append-to-block Heap %edi  *eax *(eax+4))
 5766         # reclaim tmp
 5767         81 0/subop/add %esp 8/imm32
 5768         #
 5769         e9/jump $parse-mu-block:line-loop/disp32
 5770       }
 5771       # if slice-equal?(word-slice, "var")
 5772       {
 5773 $parse-mu-block:check-for-var:
 5774         (slice-equal? %edx "var")
 5775         3d/compare-eax-and 0/imm32/false
 5776         74/jump-if-= break/disp8
 5777         # var tmp/eax: (handle block)
 5778         68/push 0/imm32
 5779         68/push 0/imm32
 5780         89/<- %eax 4/r32/esp
 5781         #
 5782         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 5783         (append-to-block Heap %edi  *eax *(eax+4))
 5784         # reclaim tmp
 5785         81 0/subop/add %esp 8/imm32
 5786         #
 5787         e9/jump $parse-mu-block:line-loop/disp32
 5788       }
 5789 $parse-mu-block:regular-stmt:
 5790       # otherwise
 5791       # var tmp/eax: (handle block)
 5792       68/push 0/imm32
 5793       68/push 0/imm32
 5794       89/<- %eax 4/r32/esp
 5795       #
 5796       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 5797       (append-to-block Heap %edi  *eax *(eax+4))
 5798       # reclaim tmp
 5799       81 0/subop/add %esp 8/imm32
 5800       #
 5801       e9/jump loop/disp32
 5802     } # end line loop
 5803     # pop(vars)
 5804     (pop *(ebp+0xc))  # => eax
 5805     (pop *(ebp+0xc))  # => eax
 5806     (pop *(ebp+0xc))  # => eax
 5807 $parse-mu-block:end:
 5808     # . reclaim locals
 5809     81 0/subop/add %esp 0x214/imm32
 5810     # . restore registers
 5811     5f/pop-to-edi
 5812     5b/pop-to-ebx
 5813     5a/pop-to-edx
 5814     59/pop-to-ecx
 5815     58/pop-to-eax
 5816     # . epilogue
 5817     89/<- %esp 5/r32/ebp
 5818     5d/pop-to-ebp
 5819     c3/return
 5820 
 5821 $parse-mu-block:abort:
 5822     # error("'{' or '}' should be on its own line, but got '")
 5823     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 5824     (rewind-stream %ecx)
 5825     (write-stream 2 %ecx)
 5826     (write-buffered *(ebp+0x18) "'\n")
 5827     (flush *(ebp+0x18))
 5828     (stop *(ebp+0x1c) 1)
 5829     # never gets here
 5830 
 5831 new-block-name:  # fn: (addr function), out: (addr handle var)
 5832     # . prologue
 5833     55/push-ebp
 5834     89/<- %ebp 4/r32/esp
 5835     # . save registers
 5836     50/push-eax
 5837     51/push-ecx
 5838     52/push-edx
 5839     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 5840     8b/-> *(ebp+8) 0/r32/eax
 5841     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5842     8b/-> *eax 0/r32/eax  # String-size
 5843     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 5844     89/<- %ecx 0/r32/eax
 5845     # var name/edx: (stream byte n)
 5846     29/subtract-from %esp 1/r32/ecx
 5847     ff 6/subop/push %ecx
 5848     68/push 0/imm32/read
 5849     68/push 0/imm32/write
 5850     89/<- %edx 4/r32/esp
 5851     (clear-stream %edx)
 5852     # eax = fn->name
 5853     8b/-> *(ebp+8) 0/r32/eax
 5854     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 5855     # construct result using Next-block-index (and increment it)
 5856     (write %edx "$")
 5857     (write %edx %eax)
 5858     (write %edx ":")
 5859     (print-int32 %edx *Next-block-index)
 5860     ff 0/subop/increment *Next-block-index
 5861     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 5862     # . eax = name->write
 5863     8b/-> *edx 0/r32/eax
 5864     # . edx = name->data
 5865     8d/copy-address *(edx+0xc) 2/r32/edx
 5866     # . eax = name->write + name->data
 5867     01/add-to %eax 2/r32/edx
 5868     # . push {edx, eax}
 5869     ff 6/subop/push %eax
 5870     ff 6/subop/push %edx
 5871     89/<- %eax 4/r32/esp
 5872     # out = new literal(s)
 5873     (new-literal Heap %eax *(ebp+0xc))
 5874 #?     8b/-> *(ebp+0xc) 0/r32/eax
 5875 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 5876 #?     (print-int32-buffered Stderr *(eax+8))
 5877 #?     (write-buffered Stderr " for var ")
 5878 #?     (print-int32-buffered Stderr %eax)
 5879 #?     (write-buffered Stderr Newline)
 5880 #?     (flush Stderr)
 5881 $new-block-name:end:
 5882     # . reclaim locals
 5883     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 5884     81 0/subop/add %ecx 8/imm32  # slice
 5885     01/add-to %esp 1/r32/ecx
 5886     # . restore registers
 5887     5a/pop-to-edx
 5888     59/pop-to-ecx
 5889     58/pop-to-eax
 5890     # . epilogue
 5891     89/<- %esp 5/r32/ebp
 5892     5d/pop-to-ebp
 5893     c3/return
 5894 
 5895 == data
 5896 
 5897 # Global state added to each var record when parsing a function
 5898 Next-block-index:  # (addr int)
 5899     1/imm32
 5900 
 5901 == code
 5902 
 5903 check-no-tokens-left:  # line: (addr stream byte)
 5904     # . prologue
 5905     55/push-ebp
 5906     89/<- %ebp 4/r32/esp
 5907     # . save registers
 5908     50/push-eax
 5909     51/push-ecx
 5910     # var s/ecx: slice
 5911     68/push 0/imm32/end
 5912     68/push 0/imm32/start
 5913     89/<- %ecx 4/r32/esp
 5914     #
 5915     (next-mu-token *(ebp+8) %ecx)
 5916     # if slice-empty?(s) return
 5917     (slice-empty? %ecx)
 5918     3d/compare-eax-and 0/imm32/false
 5919     75/jump-if-!= $check-no-tokens-left:end/disp8
 5920     # if (slice-starts-with?(s, '#') return
 5921     # . eax = *s->start
 5922     8b/-> *edx 0/r32/eax
 5923     8a/copy-byte *eax 0/r32/AL
 5924     81 4/subop/and %eax 0xff/imm32
 5925     # . if (eax == '#') continue
 5926     3d/compare-eax-and 0x23/imm32/hash
 5927     74/jump-if-= $check-no-tokens-left:end/disp8
 5928     # abort
 5929     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 5930     (rewind-stream %ecx)
 5931     (write-stream 2 %ecx)
 5932     (write-buffered Stderr "'\n")
 5933     (flush Stderr)
 5934     # . syscall(exit, 1)
 5935     bb/copy-to-ebx  1/imm32
 5936     e8/call syscall_exit/disp32
 5937     # never gets here
 5938 $check-no-tokens-left:end:
 5939     # . reclaim locals
 5940     81 0/subop/add %esp 8/imm32
 5941     # . restore registers
 5942     59/pop-to-ecx
 5943     58/pop-to-eax
 5944     # . epilogue
 5945     89/<- %esp 5/r32/ebp
 5946     5d/pop-to-ebp
 5947     c3/return
 5948 
 5949 parse-mu-named-block:  # name: (addr slice), in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 5950     # pseudocode:
 5951     #   var v: (handle var)
 5952     #   new-literal(name, v)
 5953     #   push(vars, {v, false})
 5954     #   parse-mu-block(in, vars, fn, out)
 5955     #   pop(vars)
 5956     #   out->tag = block
 5957     #   out->var = v
 5958     #
 5959     # . prologue
 5960     55/push-ebp
 5961     89/<- %ebp 4/r32/esp
 5962     # . save registers
 5963     50/push-eax
 5964     51/push-ecx
 5965     57/push-edi
 5966     # var v/ecx: (handle var)
 5967     68/push 0/imm32
 5968     68/push 0/imm32
 5969     89/<- %ecx 4/r32/esp
 5970     #
 5971     (new-literal Heap *(ebp+8) %ecx)
 5972     # push(vars, v)
 5973     (push *(ebp+0x10) *ecx)
 5974     (push *(ebp+0x10) *(ecx+4))
 5975     (push *(ebp+0x10) 0)  # false
 5976     #
 5977     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 5978     # pop v off vars
 5979     (pop *(ebp+0x10))  # => eax
 5980     (pop *(ebp+0x10))  # => eax
 5981     (pop *(ebp+0x10))  # => eax
 5982     # var out-addr/edi: (addr stmt) = lookup(*out)
 5983     8b/-> *(ebp+0x18) 7/r32/edi
 5984     (lookup *edi *(edi+4))  # => eax
 5985     89/<- %edi 0/r32/eax
 5986     # out-addr->tag = named-block
 5987     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 5988     # out-addr->var = v
 5989     8b/-> *ecx 0/r32/eax
 5990     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 5991     8b/-> *(ecx+4) 0/r32/eax
 5992     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 5993 $parse-mu-named-block:end:
 5994     # . reclaim locals
 5995     81 0/subop/add %esp 8/imm32
 5996     # . restore registers
 5997     5f/pop-to-edi
 5998     59/pop-to-ecx
 5999     58/pop-to-eax
 6000     # . epilogue
 6001     89/<- %esp 5/r32/ebp
 6002     5d/pop-to-ebp
 6003     c3/return
 6004 
 6005 parse-mu-var-def:  # line: (addr stream byte), vars: (addr stack live-var), out: (addr handle stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 6006     # . prologue
 6007     55/push-ebp
 6008     89/<- %ebp 4/r32/esp
 6009     # . save registers
 6010     50/push-eax
 6011     51/push-ecx
 6012     52/push-edx
 6013     57/push-edi
 6014     # edi = out
 6015     8b/-> *(ebp+0x10) 7/r32/edi
 6016     # var word-slice/ecx: slice
 6017     68/push 0/imm32/end
 6018     68/push 0/imm32/start
 6019     89/<- %ecx 4/r32/esp
 6020     # var v/edx: (handle var)
 6021     68/push 0/imm32
 6022     68/push 0/imm32
 6023     89/<- %edx 4/r32/esp
 6024     # v = parse-var-with-type(next-mu-token(line))
 6025     (next-mu-token *(ebp+8) %ecx)
 6026     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 6027     #
 6028     (push *(ebp+0xc) *edx)
 6029     (push *(ebp+0xc) *(edx+4))
 6030     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 6031     # either v has no register and there's no more to this line
 6032     (lookup *edx *(edx+4))  # => eax
 6033     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 6034     3d/compare-eax-and 0/imm32
 6035     {
 6036       75/jump-if-!= break/disp8
 6037       # TODO: disallow vars of type 'byte' on the stack
 6038       # ensure that there's nothing else on this line
 6039       (next-mu-token *(ebp+8) %ecx)
 6040       (slice-empty? %ecx)  # => eax
 6041       3d/compare-eax-and 0/imm32/false
 6042       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 6043       #
 6044       (new-var-def Heap  *edx *(edx+4)  %edi)
 6045       eb/jump $parse-mu-var-def:end/disp8
 6046     }
 6047     # or v has a register and there's more to this line
 6048     {
 6049       74/jump-if-= break/disp8
 6050       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 6051       # ensure that the next word is '<-'
 6052       (next-mu-token *(ebp+8) %ecx)
 6053       (slice-equal? %ecx "<-")  # => eax
 6054       3d/compare-eax-and 0/imm32/false
 6055       74/jump-if-= $parse-mu-var-def:error1/disp8
 6056       #
 6057       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 6058       (lookup *edi *(edi+4))  # => eax
 6059       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc))
 6060     }
 6061 $parse-mu-var-def:end:
 6062     # . reclaim locals
 6063     81 0/subop/add %esp 0x10/imm32
 6064     # . restore registers
 6065     5f/pop-to-edi
 6066     5a/pop-to-edx
 6067     59/pop-to-ecx
 6068     58/pop-to-eax
 6069     # . epilogue
 6070     89/<- %esp 5/r32/ebp
 6071     5d/pop-to-ebp
 6072     c3/return
 6073 
 6074 $parse-mu-var-def:error1:
 6075     (rewind-stream *(ebp+8))
 6076     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 6077     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 6078     (flush *(ebp+0x18))
 6079     (write-stream 2 *(ebp+8))
 6080     (write-buffered *(ebp+0x18) "'\n")
 6081     (flush *(ebp+0x18))
 6082     (stop *(ebp+0x1c) 1)
 6083     # never gets here
 6084 
 6085 $parse-mu-var-def:error2:
 6086     (rewind-stream *(ebp+8))
 6087     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 6088     (write-buffered *(ebp+0x18) "fn ")
 6089     8b/-> *(ebp+0x14) 0/r32/eax
 6090     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 6091     (write-buffered *(ebp+0x18) %eax)
 6092     (write-buffered *(ebp+0x18) ": var ")
 6093     # var v-addr/eax: (addr var) = lookup(v)
 6094     (lookup *edx *(edx+4))  # => eax
 6095     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6096     (write-buffered *(ebp+0x18) %eax)
 6097     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 6098     (flush *(ebp+0x18))
 6099     (stop *(ebp+0x1c) 1)
 6100     # never gets here
 6101 
 6102 test-parse-mu-var-def:
 6103     # 'var n: int'
 6104     # . prologue
 6105     55/push-ebp
 6106     89/<- %ebp 4/r32/esp
 6107     # setup
 6108     (clear-stream _test-input-stream)
 6109     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 6110     # var out/esi: (handle stmt)
 6111     68/push 0/imm32
 6112     68/push 0/imm32
 6113     89/<- %esi 4/r32/esp
 6114     # var vars/ecx: (stack (addr var) 16)
 6115     81 5/subop/subtract %esp 0xc0/imm32
 6116     68/push 0xc0/imm32/size
 6117     68/push 0/imm32/top
 6118     89/<- %ecx 4/r32/esp
 6119     (clear-stack %ecx)
 6120     # convert
 6121     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 6122     # var out-addr/esi: (addr stmt)
 6123     (lookup *esi *(esi+4))  # => eax
 6124     89/<- %esi 0/r32/eax
 6125     #
 6126     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 6127     # var v/ecx: (addr var) = lookup(out->var)
 6128     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 6129     89/<- %ecx 0/r32/eax
 6130     # v->name
 6131     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6132     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 6133     # v->register
 6134     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 6135     # v->type == int
 6136     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6137     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Tree-is-atom
 6138     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Tree-value
 6139     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Tree-right
 6140     # . epilogue
 6141     89/<- %esp 5/r32/ebp
 6142     5d/pop-to-ebp
 6143     c3/return
 6144 
 6145 test-parse-mu-reg-var-def:
 6146     # 'var n/eax: int <- copy 0'
 6147     # . prologue
 6148     55/push-ebp
 6149     89/<- %ebp 4/r32/esp
 6150     # setup
 6151     (clear-stream _test-input-stream)
 6152     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 6153     # var out/esi: (handle stmt)
 6154     68/push 0/imm32
 6155     68/push 0/imm32
 6156     89/<- %esi 4/r32/esp
 6157     # var vars/ecx: (stack (addr var) 16)
 6158     81 5/subop/subtract %esp 0xc0/imm32
 6159     68/push 0xc0/imm32/size
 6160     68/push 0/imm32/top
 6161     89/<- %ecx 4/r32/esp
 6162     (clear-stack %ecx)
 6163     # convert
 6164     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 6165     # var out-addr/esi: (addr stmt)
 6166     (lookup *esi *(esi+4))  # => eax
 6167     89/<- %esi 0/r32/eax
 6168     #
 6169     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 6170     # var v/ecx: (addr var) = lookup(out->outputs->value)
 6171     # . eax: (addr stmt-var) = lookup(out->outputs)
 6172     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 6173     # .
 6174     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 6175     # . eax: (addr var) = lookup(eax->value)
 6176     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6177     # . ecx = eax
 6178     89/<- %ecx 0/r32/eax
 6179     # v->name
 6180     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6181     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 6182     # v->register
 6183     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 6184     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 6185     # v->type == int
 6186     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6187     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Tree-is-atom
 6188     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Tree-value
 6189     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Tree-right
 6190     # . epilogue
 6191     89/<- %esp 5/r32/ebp
 6192     5d/pop-to-ebp
 6193     c3/return
 6194 
 6195 parse-mu-stmt:  # line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 6196     # pseudocode:
 6197     #   var name: slice
 6198     #   allocate(Heap, Stmt-size, out)
 6199     #   var out-addr: (addr stmt) = lookup(*out)
 6200     #   out-addr->tag = stmt
 6201     #   if stmt-has-outputs?(line)
 6202     #     while true
 6203     #       name = next-mu-token(line)
 6204     #       if (name == '<-') break
 6205     #       assert(is-identifier?(name))
 6206     #       var v: (handle var) = lookup-or-define-var(name, vars, fn)  # regular stmts may define vars in fn outputs
 6207     #       out-addr->outputs = append(v, out-addr->outputs)
 6208     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 6209     #
 6210     # . prologue
 6211     55/push-ebp
 6212     89/<- %ebp 4/r32/esp
 6213     # . save registers
 6214     50/push-eax
 6215     51/push-ecx
 6216     52/push-edx
 6217     53/push-ebx
 6218     57/push-edi
 6219     # var name/ecx: slice
 6220     68/push 0/imm32/end
 6221     68/push 0/imm32/start
 6222     89/<- %ecx 4/r32/esp
 6223     # var is-deref?/edx: boolean = false
 6224     ba/copy-to-edx 0/imm32/false
 6225     # var v: (handle var)
 6226     68/push 0/imm32
 6227     68/push 0/imm32
 6228     89/<- %ebx 4/r32/esp
 6229     #
 6230     (allocate Heap *Stmt-size *(ebp+0x14))
 6231     # var out-addr/edi: (addr stmt) = lookup(*out)
 6232     8b/-> *(ebp+0x14) 7/r32/edi
 6233     (lookup *edi *(edi+4))  # => eax
 6234     89/<- %edi 0/r32/eax
 6235     # out-addr->tag = 1/stmt
 6236     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 6237     {
 6238       (stmt-has-outputs? *(ebp+8))
 6239       3d/compare-eax-and 0/imm32/false
 6240       0f 84/jump-if-= break/disp32
 6241       {
 6242 $parse-mu-stmt:read-outputs:
 6243         # name = next-mu-token(line)
 6244         (next-mu-token *(ebp+8) %ecx)
 6245         # if slice-empty?(word-slice) break
 6246         (slice-empty? %ecx)  # => eax
 6247         3d/compare-eax-and 0/imm32/false
 6248         0f 85/jump-if-!= break/disp32
 6249         # if (name == "<-") break
 6250         (slice-equal? %ecx "<-")  # => eax
 6251         3d/compare-eax-and 0/imm32/false
 6252         0f 85/jump-if-!= break/disp32
 6253         # is-deref? = false
 6254         ba/copy-to-edx 0/imm32/false
 6255         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 6256         8b/-> *ecx 0/r32/eax  # Slice-start
 6257         8a/copy-byte *eax 0/r32/AL
 6258         81 4/subop/and %eax 0xff/imm32
 6259         3d/compare-eax-and 0x2a/imm32/asterisk
 6260         {
 6261           75/jump-if-!= break/disp8
 6262           ff 0/subop/increment *ecx
 6263           ba/copy-to-edx 1/imm32/true
 6264         }
 6265         # assert(is-identifier?(name))
 6266         (is-identifier? %ecx)  # => eax
 6267         3d/compare-eax-and 0/imm32/false
 6268         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 6269         #
 6270         (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 6271         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 6272         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 6273         #
 6274         e9/jump loop/disp32
 6275       }
 6276     }
 6277     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc))
 6278 $parse-mu-stmt:end:
 6279     # . reclaim locals
 6280     81 0/subop/add %esp 0x10/imm32
 6281     # . restore registers
 6282     5f/pop-to-edi
 6283     5b/pop-to-ebx
 6284     5a/pop-to-edx
 6285     59/pop-to-ecx
 6286     58/pop-to-eax
 6287     # . epilogue
 6288     89/<- %esp 5/r32/ebp
 6289     5d/pop-to-ebp
 6290     c3/return
 6291 
 6292 $parse-mu-stmt:abort:
 6293     # error("invalid identifier '" name "'\n")
 6294     (write-buffered *(ebp+0x18) "invalid identifier '")
 6295     (write-slice-buffered *(ebp+0x18) %ecx)
 6296     (write-buffered *(ebp+0x18) "'\n")
 6297     (flush *(ebp+0x18))
 6298     (stop *(ebp+0x1c) 1)
 6299     # never gets here
 6300 
 6301 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6302     # pseudocode:
 6303     #   stmt->name = slice-to-string(next-mu-token(line))
 6304     #   while true
 6305     #     name = next-mu-token(line)
 6306     #     v = lookup-var-or-literal(name)
 6307     #     stmt->inouts = append(v, stmt->inouts)
 6308     #
 6309     # . prologue
 6310     55/push-ebp
 6311     89/<- %ebp 4/r32/esp
 6312     # . save registers
 6313     50/push-eax
 6314     51/push-ecx
 6315     52/push-edx
 6316     53/push-ebx
 6317     56/push-esi
 6318     57/push-edi
 6319     # edi = stmt
 6320     8b/-> *(ebp+8) 7/r32/edi
 6321     # var name/ecx: slice
 6322     68/push 0/imm32/end
 6323     68/push 0/imm32/start
 6324     89/<- %ecx 4/r32/esp
 6325     # var is-deref?/edx: boolean = false
 6326     ba/copy-to-edx 0/imm32/false
 6327     # var v/esi: (handle var)
 6328     68/push 0/imm32
 6329     68/push 0/imm32
 6330     89/<- %esi 4/r32/esp
 6331 $add-operation-and-inputs-to-stmt:read-operation:
 6332     (next-mu-token *(ebp+0xc) %ecx)
 6333     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 6334     (slice-to-string Heap %ecx %eax)
 6335     # var is-get?/ebx: boolean = (name == "get")
 6336     (slice-equal? %ecx "get")  # => eax
 6337     89/<- %ebx 0/r32/eax
 6338     {
 6339 $add-operation-and-inputs-to-stmt:read-inouts:
 6340       # name = next-mu-token(line)
 6341       (next-mu-token *(ebp+0xc) %ecx)
 6342       # if slice-empty?(word-slice) break
 6343       (slice-empty? %ecx)  # => eax
 6344       3d/compare-eax-and 0/imm32/false
 6345       0f 85/jump-if-!= break/disp32
 6346       # if (name == "<-") abort
 6347       (slice-equal? %ecx "<-")
 6348       3d/compare-eax-and 0/imm32/false
 6349       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 6350       # if (is-get? && second operand) lookup or create offset
 6351       {
 6352         81 7/subop/compare %ebx 0/imm32/false
 6353         74/jump-if-= break/disp8
 6354         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6355         3d/compare-eax-and 0/imm32
 6356         74/jump-if-= break/disp8
 6357         (lookup-or-create-constant %eax %ecx %esi)
 6358 #?         (lookup *esi *(esi+4))
 6359 #?         (write-buffered Stderr "creating new output var ")
 6360 #?         (print-int32-buffered Stderr %eax)
 6361 #?         (write-buffered Stderr " for field called ")
 6362 #?         (write-slice-buffered Stderr %ecx)
 6363 #?         (write-buffered Stderr "; var name ")
 6364 #?         (lookup *eax *(eax+4))  # Var-name
 6365 #?         (write-buffered Stderr %eax)
 6366 #?         (write-buffered Stderr Newline)
 6367 #?         (flush Stderr)
 6368         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 6369       }
 6370       # is-deref? = false
 6371       ba/copy-to-edx 0/imm32/false
 6372       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 6373       8b/-> *ecx 0/r32/eax  # Slice-start
 6374       8a/copy-byte *eax 0/r32/AL
 6375       81 4/subop/and %eax 0xff/imm32
 6376       3d/compare-eax-and 0x2a/imm32/asterisk
 6377       {
 6378         75/jump-if-!= break/disp8
 6379 $add-operation-and-inputs-to-stmt:inout-is-deref:
 6380         ff 0/subop/increment *ecx
 6381         ba/copy-to-edx 1/imm32/true
 6382       }
 6383       (lookup-var-or-literal %ecx *(ebp+0x10) %esi)
 6384 $add-operation-and-inputs-to-stmt:save-var:
 6385       8d/copy-address *(edi+0xc) 0/r32/eax
 6386       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 6387       #
 6388       e9/jump loop/disp32
 6389     }
 6390 $add-operation-and-inputs-to-stmt:end:
 6391     # . reclaim locals
 6392     81 0/subop/add %esp 0x10/imm32
 6393     # . restore registers
 6394     5f/pop-to-edi
 6395     5e/pop-to-esi
 6396     5b/pop-to-ebx
 6397     5a/pop-to-edx
 6398     59/pop-to-ecx
 6399     58/pop-to-eax
 6400     # . epilogue
 6401     89/<- %esp 5/r32/ebp
 6402     5d/pop-to-ebp
 6403     c3/return
 6404 
 6405 $add-operation-and-inputs-to-stmt:abort:
 6406     # error("invalid statement '" line "'\n")
 6407     (rewind-stream *(ebp+8))
 6408     (write-buffered *(ebp+0x14) "invalid identifier '")
 6409     (flush *(ebp+0x14))
 6410     (write-stream 2 *(ebp+8))
 6411     (write-buffered *(ebp+0x14) "'\n")
 6412     (flush *(ebp+0x14))
 6413     (stop *(ebp+0x18) 1)
 6414     # never gets here
 6415 
 6416 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 6417     # . prologue
 6418     55/push-ebp
 6419     89/<- %ebp 4/r32/esp
 6420     # . save registers
 6421     51/push-ecx
 6422     # var word-slice/ecx: slice
 6423     68/push 0/imm32/end
 6424     68/push 0/imm32/start
 6425     89/<- %ecx 4/r32/esp
 6426     # result = false
 6427     b8/copy-to-eax 0/imm32/false
 6428     (rewind-stream *(ebp+8))
 6429     {
 6430       (next-mu-token *(ebp+8) %ecx)
 6431       # if slice-empty?(word-slice) break
 6432       (slice-empty? %ecx)
 6433       3d/compare-eax-and 0/imm32/false
 6434       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6435       0f 85/jump-if-!= break/disp32
 6436       # if slice-starts-with?(word-slice, '#') break
 6437       # . eax = *word-slice->start
 6438       8b/-> *ecx 0/r32/eax
 6439       8a/copy-byte *eax 0/r32/AL
 6440       81 4/subop/and %eax 0xff/imm32
 6441       # . if (eax == '#') break
 6442       3d/compare-eax-and 0x23/imm32/hash
 6443       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 6444       0f 84/jump-if-= break/disp32
 6445       # if slice-equal?(word-slice, '<-') return true
 6446       (slice-equal? %ecx "<-")
 6447       3d/compare-eax-and 0/imm32/false
 6448       74/jump-if-= loop/disp8
 6449       b8/copy-to-eax 1/imm32/true
 6450     }
 6451 $stmt-has-outputs:end:
 6452     (rewind-stream *(ebp+8))
 6453     # . reclaim locals
 6454     81 0/subop/add %esp 8/imm32
 6455     # . restore registers
 6456     59/pop-to-ecx
 6457     # . epilogue
 6458     89/<- %esp 5/r32/ebp
 6459     5d/pop-to-ebp
 6460     c3/return
 6461 
 6462 # if 'name' starts with a digit, create a new literal var for it
 6463 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 6464 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6465     # . prologue
 6466     55/push-ebp
 6467     89/<- %ebp 4/r32/esp
 6468     # . save registers
 6469     50/push-eax
 6470     51/push-ecx
 6471     56/push-esi
 6472     # esi = name
 6473     8b/-> *(ebp+8) 6/r32/esi
 6474     # if slice-empty?(name) abort
 6475     (slice-empty? %esi)  # => eax
 6476     3d/compare-eax-and 0/imm32/false
 6477     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 6478     # var c/ecx: byte = *name->start
 6479     8b/-> *esi 1/r32/ecx
 6480     8a/copy-byte *ecx 1/r32/CL
 6481     81 4/subop/and %ecx 0xff/imm32
 6482     # if is-decimal-digit?(c) return new var(name)
 6483     {
 6484       (is-decimal-digit? %ecx)  # => eax
 6485       3d/compare-eax-and 0/imm32/false
 6486       74/jump-if-= break/disp8
 6487       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
 6488       eb/jump $lookup-var-or-literal:end/disp8
 6489     }
 6490     # else if (c == '"') return new var(name)
 6491     {
 6492       81 7/subop/compare %ecx 0x22/imm32/dquote
 6493       75/jump-if-!= break/disp8
 6494       (new-literal Heap %esi *(ebp+0x10))
 6495       eb/jump $lookup-var-or-literal:end/disp8
 6496     }
 6497     # otherwise return lookup-var(name, vars)
 6498     {
 6499       (lookup-var %esi *(ebp+0xc))  # => eax
 6500     }
 6501 $lookup-var-or-literal:end:
 6502     # . restore registers
 6503     5e/pop-to-esi
 6504     59/pop-to-ecx
 6505     58/pop-to-eax
 6506     # . epilogue
 6507     89/<- %esp 5/r32/ebp
 6508     5d/pop-to-ebp
 6509     c3/return
 6510 
 6511 $lookup-var-or-literal:abort:
 6512     (write-buffered *(ebp+0x14) "empty variable!")
 6513     (flush *(ebp+0x14))
 6514     (stop *(ebp+0x18) 1)
 6515     # never gets here
 6516 
 6517 # return first 'name' from the top (back) of 'vars' and abort if not found
 6518 lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6519     # . prologue
 6520     55/push-ebp
 6521     89/<- %ebp 4/r32/esp
 6522     # . save registers
 6523     50/push-eax
 6524     #
 6525     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6526     # if (*out == 0) abort
 6527     8b/-> *(ebp+0x10) 0/r32/eax
 6528     81 7/subop/compare *eax 0/imm32
 6529     74/jump-if-= $lookup-var:abort/disp8
 6530 $lookup-var:end:
 6531     # . restore registers
 6532     58/pop-to-eax
 6533     # . epilogue
 6534     89/<- %esp 5/r32/ebp
 6535     5d/pop-to-ebp
 6536     c3/return
 6537 
 6538 $lookup-var:abort:
 6539     (write-buffered *(ebp+0x14) "unknown variable '")
 6540     (write-slice-buffered *(ebp+0x14) *(ebp+8))
 6541     (write-buffered *(ebp+0x14) "'\n")
 6542     (flush *(ebp+0x14))
 6543     (stop *(ebp+0x18) 1)
 6544     # never gets here
 6545 
 6546 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 6547 lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6548     # pseudocode:
 6549     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 6550     #   var min = vars->data
 6551     #   while curr >= min
 6552     #     var v: (handle var) = *curr
 6553     #     if v->name == name
 6554     #       return
 6555     #     curr -= 12
 6556     #
 6557     # . prologue
 6558     55/push-ebp
 6559     89/<- %ebp 4/r32/esp
 6560     # . save registers
 6561     50/push-eax
 6562     51/push-ecx
 6563     52/push-edx
 6564     53/push-ebx
 6565     56/push-esi
 6566     # clear out
 6567     (zero-out *(ebp+0x10) *Handle-size)
 6568     # esi = vars
 6569     8b/-> *(ebp+0xc) 6/r32/esi
 6570     # ebx = vars->top
 6571     8b/-> *esi 3/r32/ebx
 6572     # if (vars->top > vars->size) abort
 6573     3b/compare<- *(esi+4) 0/r32/eax
 6574     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 6575     # var min/edx: (addr handle var) = vars->data
 6576     8d/copy-address *(esi+8) 2/r32/edx
 6577     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 6578     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 6579     {
 6580       # if (curr < min) return
 6581       39/compare %ebx 2/r32/edx
 6582       0f 82/jump-if-addr< break/disp32
 6583       # var v/ecx: (addr var) = lookup(*curr)
 6584       (lookup *ebx *(ebx+4))  # => eax
 6585       89/<- %ecx 0/r32/eax
 6586       # var vn/eax: (addr array byte) = lookup(v->name)
 6587       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 6588       # if (vn == name) return curr
 6589       (slice-equal? *(ebp+8) %eax)  # => eax
 6590       3d/compare-eax-and 0/imm32/false
 6591       {
 6592         74/jump-if-= break/disp8
 6593         # esi = out
 6594         8b/-> *(ebp+0x10) 6/r32/esi
 6595         # *out = *curr
 6596         8b/-> *ebx 0/r32/eax
 6597         89/<- *esi 0/r32/eax
 6598         8b/-> *(ebx+4) 0/r32/eax
 6599         89/<- *(esi+4) 0/r32/eax
 6600         # return
 6601         eb/jump $lookup-var-helper:end/disp8
 6602       }
 6603       # curr -= 12
 6604       81 5/subop/subtract %ebx 0xc/imm32
 6605       e9/jump loop/disp32
 6606     }
 6607 $lookup-var-helper:end:
 6608     # . restore registers
 6609     5e/pop-to-esi
 6610     5b/pop-to-ebx
 6611     5a/pop-to-edx
 6612     59/pop-to-ecx
 6613     58/pop-to-eax
 6614     # . epilogue
 6615     89/<- %esp 5/r32/ebp
 6616     5d/pop-to-ebp
 6617     c3/return
 6618 
 6619 $lookup-var-helper:error1:
 6620     (write-buffered *(ebp+0x14) "malformed stack when looking up '")
 6621     (write-slice-buffered *(ebp+0x14) *(ebp+8))
 6622     (write-buffered *(ebp+0x14) "'\n")
 6623     (flush *(ebp+0x14))
 6624     (stop *(ebp+0x18) 1)
 6625     # never gets here
 6626 
 6627 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 6628 lookup-or-define-var:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6629     # . prologue
 6630     55/push-ebp
 6631     89/<- %ebp 4/r32/esp
 6632     # . save registers
 6633     50/push-eax
 6634     #
 6635     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14))
 6636     {
 6637       # if (out != 0) return
 6638       8b/-> *(ebp+0x14) 0/r32/eax
 6639       81 7/subop/compare *eax 0/imm32
 6640       75/jump-if-!= break/disp8
 6641       # if name is one of fn's outputs, return it
 6642       {
 6643         (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 6644         8b/-> *(ebp+0x14) 0/r32/eax
 6645         81 7/subop/compare *eax 0/imm32
 6646         # otherwise abort
 6647         0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 6648         # update vars
 6649         (push *(ebp+0xc) *eax)
 6650         (push *(ebp+0xc) *(eax+4))
 6651         (push *(ebp+0xc) 0)  # never spill fn-outputs
 6652       }
 6653     }
 6654 $lookup-or-define-var:end:
 6655     # . restore registers
 6656     58/pop-to-eax
 6657     # . epilogue
 6658     89/<- %esp 5/r32/ebp
 6659     5d/pop-to-ebp
 6660     c3/return
 6661 
 6662 $lookup-or-define-var:abort:
 6663     (write-buffered *(ebp+0x18) "unknown variable '")
 6664     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 6665     (write-buffered *(ebp+0x18) "'\n")
 6666     (flush *(ebp+0x18))
 6667     (stop *(ebp+0x1c) 1)
 6668     # never gets here
 6669 
 6670 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 6671     # . prologue
 6672     55/push-ebp
 6673     89/<- %ebp 4/r32/esp
 6674     # . save registers
 6675     50/push-eax
 6676     51/push-ecx
 6677     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 6678     8b/-> *(ebp+8) 1/r32/ecx
 6679     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 6680     89/<- %ecx 0/r32/eax
 6681     # while curr != null
 6682     {
 6683       81 7/subop/compare %ecx 0/imm32
 6684       74/jump-if-= break/disp8
 6685       # var v/eax: (addr var) = lookup(curr->value)
 6686       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 6687       # var s/eax: (addr array byte) = lookup(v->name)
 6688       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6689       # if (s == name) return curr->value
 6690       (slice-equal? *(ebp+0xc) %eax)  # => eax
 6691       3d/compare-eax-and 0/imm32/false
 6692       {
 6693         74/jump-if-= break/disp8
 6694         # var edi = out
 6695         57/push-edi
 6696         8b/-> *(ebp+0x10) 7/r32/edi
 6697         # *out = curr->value
 6698         8b/-> *ecx 0/r32/eax
 6699         89/<- *edi 0/r32/eax
 6700         8b/-> *(ecx+4) 0/r32/eax
 6701         89/<- *(edi+4) 0/r32/eax
 6702         #
 6703         5f/pop-to-edi
 6704         eb/jump $find-in-function-outputs:end/disp8
 6705       }
 6706       # curr = curr->next
 6707       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 6708       89/<- %ecx 0/r32/eax
 6709       #
 6710       eb/jump loop/disp8
 6711     }
 6712     b8/copy-to-eax 0/imm32
 6713 $find-in-function-outputs:end:
 6714     # . restore registers
 6715     59/pop-to-ecx
 6716     58/pop-to-eax
 6717     # . epilogue
 6718     89/<- %esp 5/r32/ebp
 6719     5d/pop-to-ebp
 6720     c3/return
 6721 
 6722 test-parse-mu-stmt:
 6723     # . prologue
 6724     55/push-ebp
 6725     89/<- %ebp 4/r32/esp
 6726     # setup
 6727     (clear-stream _test-input-stream)
 6728     (write _test-input-stream "increment n\n")
 6729     # var vars/ecx: (stack (addr var) 16)
 6730     81 5/subop/subtract %esp 0xc0/imm32
 6731     68/push 0xc0/imm32/size
 6732     68/push 0/imm32/top
 6733     89/<- %ecx 4/r32/esp
 6734     (clear-stack %ecx)
 6735     # var v/edx: (handle var)
 6736     68/push 0/imm32
 6737     68/push 0/imm32
 6738     89/<- %edx 4/r32/esp
 6739     # var s/eax: (handle array byte)
 6740     68/push 0/imm32
 6741     68/push 0/imm32
 6742     89/<- %eax 4/r32/esp
 6743     # v = new var("n")
 6744     (copy-array Heap "n" %eax)
 6745     (new-var Heap *eax *(eax+4) %edx)
 6746     #
 6747     (push %ecx *edx)
 6748     (push %ecx *(edx+4))
 6749     (push %ecx 0)
 6750     # var out/eax: (handle stmt)
 6751     68/push 0/imm32
 6752     68/push 0/imm32
 6753     89/<- %eax 4/r32/esp
 6754     # convert
 6755     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 6756     # var out-addr/edx: (addr stmt) = lookup(*out)
 6757     (lookup *eax *(eax+4))  # => eax
 6758     89/<- %edx 0/r32/eax
 6759     # out->tag
 6760     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 6761     # out->operation
 6762     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6763     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 6764     # out->inouts->value->name
 6765     # . eax = out->inouts
 6766     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6767     # . eax = out->inouts->value
 6768     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6769     # . eax = out->inouts->value->name
 6770     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6771     # .
 6772     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 6773     # . epilogue
 6774     89/<- %esp 5/r32/ebp
 6775     5d/pop-to-ebp
 6776     c3/return
 6777 
 6778 test-parse-mu-stmt-with-comma:
 6779     # . prologue
 6780     55/push-ebp
 6781     89/<- %ebp 4/r32/esp
 6782     # setup
 6783     (clear-stream _test-input-stream)
 6784     (write _test-input-stream "copy-to n, 3\n")
 6785     # var vars/ecx: (stack (addr var) 16)
 6786     81 5/subop/subtract %esp 0xc0/imm32
 6787     68/push 0xc0/imm32/size
 6788     68/push 0/imm32/top
 6789     89/<- %ecx 4/r32/esp
 6790     (clear-stack %ecx)
 6791     # var v/edx: (handle var)
 6792     68/push 0/imm32
 6793     68/push 0/imm32
 6794     89/<- %edx 4/r32/esp
 6795     # var s/eax: (handle array byte)
 6796     68/push 0/imm32
 6797     68/push 0/imm32
 6798     89/<- %eax 4/r32/esp
 6799     # v = new var("n")
 6800     (copy-array Heap "n" %eax)
 6801     (new-var Heap *eax *(eax+4) %edx)
 6802     #
 6803     (push %ecx *edx)
 6804     (push %ecx *(edx+4))
 6805     (push %ecx 0)
 6806     # var out/eax: (handle stmt)
 6807     68/push 0/imm32
 6808     68/push 0/imm32
 6809     89/<- %eax 4/r32/esp
 6810     # convert
 6811     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 6812     # var out-addr/edx: (addr stmt) = lookup(*out)
 6813     (lookup *eax *(eax+4))  # => eax
 6814     89/<- %edx 0/r32/eax
 6815     # out->tag
 6816     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 6817     # out->operation
 6818     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 6819     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 6820     # out->inouts->value->name
 6821     # . eax = out->inouts
 6822     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 6823     # . eax = out->inouts->value
 6824     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 6825     # . eax = out->inouts->value->name
 6826     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6827     # .
 6828     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 6829     # . epilogue
 6830     89/<- %esp 5/r32/ebp
 6831     5d/pop-to-ebp
 6832     c3/return
 6833 
 6834 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 6835     # . prologue
 6836     55/push-ebp
 6837     89/<- %ebp 4/r32/esp
 6838     # . save registers
 6839     50/push-eax
 6840     51/push-ecx
 6841     # ecx = out
 6842     8b/-> *(ebp+0x14) 1/r32/ecx
 6843     #
 6844     (allocate *(ebp+8) *Var-size %ecx)
 6845     # var out-addr/eax: (addr var)
 6846     (lookup *ecx *(ecx+4))  # => eax
 6847     # out-addr->name = name
 6848     8b/-> *(ebp+0xc) 1/r32/ecx
 6849     89/<- *eax 1/r32/ecx  # Var-name
 6850     8b/-> *(ebp+0x10) 1/r32/ecx
 6851     89/<- *(eax+4) 1/r32/ecx  # Var-name
 6852 #?     (write-buffered Stderr "var ")
 6853 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 6854 #?     (write-buffered Stderr %eax)
 6855 #?     (write-buffered Stderr " at ")
 6856 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 6857 #?     (lookup *ecx *(ecx+4))  # => eax
 6858 #?     (print-int32-buffered Stderr %eax)
 6859 #?     (write-buffered Stderr Newline)
 6860 #?     (flush Stderr)
 6861 $new-var:end:
 6862     # . restore registers
 6863     59/pop-to-ecx
 6864     58/pop-to-eax
 6865     # . epilogue
 6866     89/<- %esp 5/r32/ebp
 6867     5d/pop-to-ebp
 6868     c3/return
 6869 
 6870 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6871     # . prologue
 6872     55/push-ebp
 6873     89/<- %ebp 4/r32/esp
 6874     # . save registers
 6875     50/push-eax
 6876     51/push-ecx
 6877     # if (!is-hex-int?(name)) abort
 6878     (is-hex-int? *(ebp+0xc))  # => eax
 6879     3d/compare-eax-and 0/imm32/false
 6880     0f 84/jump-if-= $new-literal-integer:abort/disp32
 6881     # out = new var(s)
 6882     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 6883     # var out-addr/ecx: (addr var) = lookup(*out)
 6884     8b/-> *(ebp+0x10) 0/r32/eax
 6885     (lookup *eax *(eax+4))  # => eax
 6886     89/<- %ecx 0/r32/eax
 6887     # out-addr->type = new tree()
 6888     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6889     (allocate *(ebp+8) *Tree-size %eax)
 6890     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6891     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6892     # nothing else to do; default type is 'literal'
 6893 $new-literal-integer:end:
 6894     # . reclaim locals
 6895     81 0/subop/add %esp 8/imm32
 6896     # . restore registers
 6897     59/pop-to-ecx
 6898     58/pop-to-eax
 6899     # . epilogue
 6900     89/<- %esp 5/r32/ebp
 6901     5d/pop-to-ebp
 6902     c3/return
 6903 
 6904 $new-literal-integer:abort:
 6905     (write-buffered *(ebp+0x14) "variable cannot begin with a digit '")
 6906     (write-slice-buffered *(ebp+0x14) *(ebp+0xc))
 6907     (write-buffered *(ebp+0x14) "'\n")
 6908     (flush *(ebp+0x14))
 6909     (stop *(ebp+0x18) 1)
 6910     # never gets here
 6911 
 6912 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6913     # . prologue
 6914     55/push-ebp
 6915     89/<- %ebp 4/r32/esp
 6916     # . save registers
 6917     50/push-eax
 6918     51/push-ecx
 6919     # var s/ecx: (handle array byte)
 6920     68/push 0/imm32
 6921     68/push 0/imm32
 6922     89/<- %ecx 4/r32/esp
 6923     # s = slice-to-string(name)
 6924     (slice-to-string Heap *(ebp+0xc) %ecx)
 6925     # allocate to out
 6926     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6927     # var out-addr/ecx: (addr var) = lookup(*out)
 6928     8b/-> *(ebp+0x10) 1/r32/ecx
 6929     (lookup *ecx *(ecx+4))  # => eax
 6930     89/<- %ecx 0/r32/eax
 6931     # out-addr->type/eax = new type
 6932     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 6933     (allocate *(ebp+8) *Tree-size %eax)
 6934     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 6935     # nothing else to do; default type is 'literal'
 6936     c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 6937 $new-literal:end:
 6938     # . reclaim locals
 6939     81 0/subop/add %esp 8/imm32
 6940     # . restore registers
 6941     59/pop-to-ecx
 6942     58/pop-to-eax
 6943     # . epilogue
 6944     89/<- %esp 5/r32/ebp
 6945     5d/pop-to-ebp
 6946     c3/return
 6947 
 6948 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 6949     # . prologue
 6950     55/push-ebp
 6951     89/<- %ebp 4/r32/esp
 6952     # . save registers
 6953     51/push-ecx
 6954     # var tmp/ecx: (handle array byte)
 6955     68/push 0/imm32
 6956     68/push 0/imm32
 6957     89/<- %ecx 4/r32/esp
 6958     # tmp = slice-to-string(name)
 6959     (slice-to-string Heap *(ebp+0xc) %ecx)
 6960     # out = new-var(tmp)
 6961     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 6962 $new-var-from-slice:end:
 6963     # . reclaim locals
 6964     81 0/subop/add %esp 8/imm32
 6965     # . restore registers
 6966     59/pop-to-ecx
 6967     # . epilogue
 6968     89/<- %esp 5/r32/ebp
 6969     5d/pop-to-ebp
 6970     c3/return
 6971 
 6972 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 6973     # . prologue
 6974     55/push-ebp
 6975     89/<- %ebp 4/r32/esp
 6976     # . save registers
 6977     50/push-eax
 6978     51/push-ecx
 6979     #
 6980     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 6981     # var out-addr/eax: (addr stmt) = lookup(*out)
 6982     8b/-> *(ebp+0x14) 0/r32/eax
 6983     (lookup *eax *(eax+4))  # => eax
 6984     # out-addr->tag = stmt
 6985     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 6986     # result->var = var
 6987     8b/-> *(ebp+0xc) 1/r32/ecx
 6988     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 6989     8b/-> *(ebp+0x10) 1/r32/ecx
 6990     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 6991 $new-var-def:end:
 6992     # . restore registers
 6993     59/pop-to-ecx
 6994     58/pop-to-eax
 6995     # . epilogue
 6996     89/<- %esp 5/r32/ebp
 6997     5d/pop-to-ebp
 6998     c3/return
 6999 
 7000 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 7001     # . prologue
 7002     55/push-ebp
 7003     89/<- %ebp 4/r32/esp
 7004     # . save registers
 7005     50/push-eax
 7006     # eax = out
 7007     8b/-> *(ebp+0x14) 0/r32/eax
 7008     #
 7009     (allocate *(ebp+8) *Stmt-size %eax)
 7010     # var out-addr/eax: (addr stmt) = lookup(*out)
 7011     (lookup *eax *(eax+4))  # => eax
 7012     # set tag
 7013     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 7014     # set output
 7015     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 7016     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 7017 $new-reg-var-def:end:
 7018     # . restore registers
 7019     58/pop-to-eax
 7020     # . epilogue
 7021     89/<- %esp 5/r32/ebp
 7022     5d/pop-to-ebp
 7023     c3/return
 7024 
 7025 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 7026     # . prologue
 7027     55/push-ebp
 7028     89/<- %ebp 4/r32/esp
 7029     # . save registers
 7030     50/push-eax
 7031     51/push-ecx
 7032     57/push-edi
 7033     # edi = out
 7034     8b/-> *(ebp+0x1c) 7/r32/edi
 7035     # *out = new list
 7036     (allocate *(ebp+8) *List-size %edi)
 7037     # var out-addr/edi: (addr list _type) = lookup(*out)
 7038     (lookup *edi *(edi+4))  # => eax
 7039     89/<- %edi 0/r32/eax
 7040     # out-addr->value = value
 7041     8b/-> *(ebp+0xc) 0/r32/eax
 7042     89/<- *edi 0/r32/eax  # List-value
 7043     8b/-> *(ebp+0x10) 0/r32/eax
 7044     89/<- *(edi+4) 0/r32/eax  # List-value
 7045     # if (list == null) return
 7046     81 7/subop/compare *(ebp+0x14) 0/imm32
 7047     74/jump-if-= $append-list:end/disp8
 7048     # otherwise append
 7049 $append-list:non-empty-list:
 7050     # var curr/eax: (addr list _type) = lookup(list)
 7051     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 7052     # while (curr->next != null) curr = curr->next
 7053     {
 7054       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 7055       74/jump-if-= break/disp8
 7056       # curr = lookup(curr->next)
 7057       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 7058       #
 7059       eb/jump loop/disp8
 7060     }
 7061     # edi = out
 7062     8b/-> *(ebp+0x1c) 7/r32/edi
 7063     # curr->next = out
 7064     8b/-> *edi 1/r32/ecx
 7065     89/<- *(eax+8) 1/r32/ecx  # List-next
 7066     8b/-> *(edi+4) 1/r32/ecx
 7067     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 7068     # out = list
 7069     8b/-> *(ebp+0x14) 1/r32/ecx
 7070     89/<- *edi 1/r32/ecx
 7071     8b/-> *(ebp+0x18) 1/r32/ecx
 7072     89/<- *(edi+4) 1/r32/ecx
 7073 $append-list:end:
 7074     # . restore registers
 7075     5f/pop-to-edi
 7076     59/pop-to-ecx
 7077     58/pop-to-eax
 7078     # . epilogue
 7079     89/<- %esp 5/r32/ebp
 7080     5d/pop-to-ebp
 7081     c3/return
 7082 
 7083 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 7084     # . prologue
 7085     55/push-ebp
 7086     89/<- %ebp 4/r32/esp
 7087     # . save registers
 7088     50/push-eax
 7089     51/push-ecx
 7090     57/push-edi
 7091     # edi = out
 7092     8b/-> *(ebp+0x20) 7/r32/edi
 7093     # out = new stmt-var
 7094     (allocate *(ebp+8) *Stmt-var-size %edi)
 7095     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 7096     (lookup *edi *(edi+4))  # => eax
 7097     89/<- %ecx 0/r32/eax
 7098     # out-addr->value = v
 7099     8b/-> *(ebp+0xc) 0/r32/eax
 7100     89/<- *ecx 0/r32/eax  # Stmt-var-value
 7101     8b/-> *(ebp+0x10) 0/r32/eax
 7102     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 7103     # out-addr->is-deref? = is-deref?
 7104     8b/-> *(ebp+0x1c) 0/r32/eax
 7105     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 7106     # if (vars == null) return result
 7107     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 7108     74/jump-if-= $append-stmt-var:end/disp8
 7109     # otherwise append
 7110     # var curr/eax: (addr stmt-var) = lookup(vars)
 7111     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 7112     # while (curr->next != null) curr = curr->next
 7113     {
 7114       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 7115       74/jump-if-= break/disp8
 7116       # curr = lookup(curr->next)
 7117       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 7118       #
 7119       eb/jump loop/disp8
 7120     }
 7121     # curr->next = out
 7122     8b/-> *edi 1/r32/ecx
 7123     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 7124     8b/-> *(edi+4) 1/r32/ecx
 7125     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 7126     # out = vars
 7127     8b/-> *(ebp+0x14) 1/r32/ecx
 7128     89/<- *edi 1/r32/ecx
 7129     8b/-> *(ebp+0x18) 1/r32/ecx
 7130     89/<- *(edi+4) 1/r32/ecx
 7131 $append-stmt-var:end:
 7132     # . restore registers
 7133     5f/pop-to-edi
 7134     59/pop-to-ecx
 7135     58/pop-to-eax
 7136     # . epilogue
 7137     89/<- %esp 5/r32/ebp
 7138     5d/pop-to-ebp
 7139     c3/return
 7140 
 7141 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 7142     # . prologue
 7143     55/push-ebp
 7144     89/<- %ebp 4/r32/esp
 7145     # . save registers
 7146     50/push-eax
 7147     56/push-esi
 7148     # esi = block
 7149     8b/-> *(ebp+0xc) 6/r32/esi
 7150     # block->stmts = append(x, block->stmts)
 7151     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 7152     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 7153 $append-to-block:end:
 7154     # . restore registers
 7155     5e/pop-to-esi
 7156     58/pop-to-eax
 7157     # . epilogue
 7158     89/<- %esp 5/r32/ebp
 7159     5d/pop-to-ebp
 7160     c3/return
 7161 
 7162 ## Parsing types
 7163 # We need to create metadata on user-defined types, and we need to use this
 7164 # metadata as we parse instructions.
 7165 # However, we also want to allow types to be used before their definitions.
 7166 # This means we can't ever assume any type data structures exist.
 7167 
 7168 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 7169     # . prologue
 7170     55/push-ebp
 7171     89/<- %ebp 4/r32/esp
 7172     # . save registers
 7173     50/push-eax
 7174     56/push-esi
 7175     # var container-type/esi: type-id
 7176     (container-type *(ebp+8))  # => eax
 7177     89/<- %esi 0/r32/eax
 7178     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 7179     68/push 0/imm32
 7180     68/push 0/imm32
 7181     89/<- %eax 4/r32/esp
 7182     (find-or-create-typeinfo %esi %eax)
 7183     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 7184     (lookup *eax *(eax+4))  # => eax
 7185     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 7186 #?     (write-buffered Stderr "constant: ")
 7187 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7188 #?     (write-buffered Stderr Newline)
 7189 #?     (flush Stderr)
 7190     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 7191 #?     8b/-> *(ebp+0x10) 0/r32/eax
 7192 #?     (write-buffered Stderr "@")
 7193 #?     (lookup *eax *(eax+4))
 7194 #?     (print-int32-buffered Stderr %eax)
 7195 #?     (lookup *eax *(eax+4))
 7196 #?     (write-buffered Stderr %eax)
 7197 #?     (write-buffered Stderr Newline)
 7198 #?     (flush Stderr)
 7199 #?     (write-buffered Stderr "offset: ")
 7200 #?     8b/-> *(eax+0x14) 0/r32/eax
 7201 #?     (print-int32-buffered Stderr %eax)
 7202 #?     (write-buffered Stderr Newline)
 7203 #?     (flush Stderr)
 7204 $lookup-or-create-constant:end:
 7205     # . reclaim locals
 7206     81 0/subop/add %esp 8/imm32
 7207     # . restore registers
 7208     5e/pop-to-esi
 7209     58/pop-to-eax
 7210     # . epilogue
 7211     89/<- %esp 5/r32/ebp
 7212     5d/pop-to-ebp
 7213     c3/return
 7214 
 7215 # if addr var:
 7216 #   container->var->type->right->left->value
 7217 # otherwise
 7218 #   container->var->type->value
 7219 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 7220     # . prologue
 7221     55/push-ebp
 7222     89/<- %ebp 4/r32/esp
 7223     #
 7224     8b/-> *(ebp+8) 0/r32/eax
 7225     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 7226     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 7227     {
 7228       81 7/subop/compare *(eax+8) 0/imm32  # Tree-right
 7229       74/jump-if-= break/disp8
 7230       (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
 7231       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 7232     }
 7233     8b/-> *(eax+4) 0/r32/eax  # Tree-value
 7234 $container-type:end:
 7235     # . epilogue
 7236     89/<- %esp 5/r32/ebp
 7237     5d/pop-to-ebp
 7238     c3/return
 7239 
 7240 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 7241     # . prologue
 7242     55/push-ebp
 7243     89/<- %ebp 4/r32/esp
 7244     # . save registers
 7245     50/push-eax
 7246     51/push-ecx
 7247     52/push-edx
 7248     57/push-edi
 7249     # edi = out
 7250     8b/-> *(ebp+0xc) 7/r32/edi
 7251     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 7252     68/push 0/imm32
 7253     68/push 0/imm32
 7254     89/<- %ecx 4/r32/esp
 7255     # find-typeinfo(t, out)
 7256     (find-typeinfo *(ebp+8) %edi)
 7257     {
 7258       # if (*out != 0) break
 7259       81 7/subop/compare *edi 0/imm32
 7260       0f 85/jump-if-!= break/disp32
 7261 $find-or-create-typeinfo:create:
 7262       # *out = allocate
 7263       (allocate Heap *Typeinfo-size %edi)
 7264       # var tmp/eax: (addr typeinfo) = lookup(*out)
 7265       (lookup *edi *(edi+4))  # => eax
 7266 #?     (write-buffered Stderr "created typeinfo at ")
 7267 #?     (print-int32-buffered Stderr %eax)
 7268 #?     (write-buffered Stderr " for type-id ")
 7269 #?     (print-int32-buffered Stderr *(ebp+8))
 7270 #?     (write-buffered Stderr Newline)
 7271 #?     (flush Stderr)
 7272       # tmp->id = t
 7273       8b/-> *(ebp+8) 2/r32/edx
 7274       89/<- *eax 2/r32/edx  # Typeinfo-id
 7275       # tmp->fields = new table
 7276       # . fields = new table
 7277       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 7278       # . tmp->fields = fields
 7279       8b/-> *ecx 2/r32/edx
 7280       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 7281       8b/-> *(ecx+4) 2/r32/edx
 7282       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 7283       # tmp->next = Program->types
 7284       8b/-> *_Program-types 1/r32/ecx
 7285       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 7286       8b/-> *_Program-types->payload 1/r32/ecx
 7287       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 7288       # Program->types = out
 7289       8b/-> *edi 1/r32/ecx
 7290       89/<- *_Program-types 1/r32/ecx
 7291       8b/-> *(edi+4) 1/r32/ecx
 7292       89/<- *_Program-types->payload 1/r32/ecx
 7293     }
 7294 $find-or-create-typeinfo:end:
 7295     # . reclaim locals
 7296     81 0/subop/add %esp 8/imm32
 7297     # . restore registers
 7298     5f/pop-to-edi
 7299     5a/pop-to-edx
 7300     59/pop-to-ecx
 7301     58/pop-to-eax
 7302     # . epilogue
 7303     89/<- %esp 5/r32/ebp
 7304     5d/pop-to-ebp
 7305     c3/return
 7306 
 7307 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 7308     # . prologue
 7309     55/push-ebp
 7310     89/<- %ebp 4/r32/esp
 7311     # . save registers
 7312     50/push-eax
 7313     51/push-ecx
 7314     52/push-edx
 7315     57/push-edi
 7316     # ecx = t
 7317     8b/-> *(ebp+8) 1/r32/ecx
 7318     # edi = out
 7319     8b/-> *(ebp+0xc) 7/r32/edi
 7320     # *out = Program->types
 7321     8b/-> *_Program-types 0/r32/eax
 7322     89/<- *edi 0/r32/eax
 7323     8b/-> *_Program-types->payload 0/r32/eax
 7324     89/<- *(edi+4) 0/r32/eax
 7325     {
 7326       # if (*out == 0) break
 7327       81 7/subop/compare *edi 0/imm32
 7328       74/jump-if-= break/disp8
 7329       # var tmp/eax: (addr typeinfo) = lookup(*out)
 7330       (lookup *edi *(edi+4))  # => eax
 7331       # if (tmp->id == t) break
 7332       39/compare *eax 1/r32/ecx  # Typeinfo-id
 7333       74/jump-if-= break/disp8
 7334       # *out = tmp->next
 7335       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 7336       89/<- *edi 2/r32/edx
 7337       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 7338       89/<- *(edi+4) 2/r32/edx
 7339       #
 7340       eb/jump loop/disp8
 7341     }
 7342 $find-typeinfo:end:
 7343     # . restore registers
 7344     5f/pop-to-edi
 7345     5a/pop-to-edx
 7346     59/pop-to-ecx
 7347     58/pop-to-eax
 7348     # . epilogue
 7349     89/<- %esp 5/r32/ebp
 7350     5d/pop-to-ebp
 7351     c3/return
 7352 
 7353 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 7354     # . prologue
 7355     55/push-ebp
 7356     89/<- %ebp 4/r32/esp
 7357     # . save registers
 7358     50/push-eax
 7359     52/push-edx
 7360     57/push-edi
 7361     # var dest/edi: (handle typeinfo-entry)
 7362     68/push 0/imm32
 7363     68/push 0/imm32
 7364     89/<- %edi 4/r32/esp
 7365     # find-or-create-typeinfo-fields(T, f, dest)
 7366     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 7367     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 7368     (lookup *edi *(edi+4))  # => eax
 7369     89/<- %edi 0/r32/eax
 7370     # if dest-addr->output-var doesn't exist, create it
 7371     {
 7372       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 7373       0f 85/jump-if-!= break/disp32
 7374       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 7375       # . var name/eax: (handle array byte) = "field"
 7376       68/push 0/imm32
 7377       68/push 0/imm32
 7378       89/<- %eax 4/r32/esp
 7379       (copy-array Heap "field" %eax)
 7380       # . new var
 7381       8d/copy-address *(edi+0xc) 2/r32/edx
 7382       (new-var Heap  *eax *(eax+4)  %edx)
 7383       # . reclaim name
 7384       81 0/subop/add %esp 8/imm32
 7385       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 7386       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 7387       89/<- %edx 0/r32/eax
 7388       # result->type = new constant type
 7389       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 7390       (allocate Heap *Tree-size %eax)
 7391       (lookup *(edx+8) *(edx+0xc))  # => eax
 7392       c7 0/subop/copy *eax 1/imm32/true  # Tree-is-atom
 7393       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Tree-value
 7394       c7 0/subop/copy *(eax+8) 0/imm32  # Tree-left
 7395       c7 0/subop/copy *(eax+0xc) 0/imm32  # Tree-right
 7396       c7 0/subop/copy *(eax+0x10) 0/imm32  # Tree-right
 7397       # result->offset isn't filled out yet
 7398       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 7399     }
 7400     # out = dest-addr->output-var
 7401     8b/-> *(ebp+0x10) 2/r32/edx
 7402     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7403     89/<- *edx 0/r32/eax
 7404     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 7405     89/<- *(edx+4) 0/r32/eax
 7406 $find-or-create-typeinfo-output-var:end:
 7407     # . reclaim locals
 7408     81 0/subop/add %esp 8/imm32
 7409     # . restore registers
 7410     5f/pop-to-edi
 7411     5a/pop-to-edx
 7412     58/pop-to-eax
 7413     # . epilogue
 7414     89/<- %esp 5/r32/ebp
 7415     5d/pop-to-ebp
 7416     c3/return
 7417 
 7418 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
 7419     # . prologue
 7420     55/push-ebp
 7421     89/<- %ebp 4/r32/esp
 7422     # . save registers
 7423     50/push-eax
 7424     56/push-esi
 7425     57/push-edi
 7426     # eax = lookup(T->fields)
 7427     8b/-> *(ebp+8) 0/r32/eax
 7428     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 7429     # edi = out
 7430     8b/-> *(ebp+0x10) 7/r32/edi
 7431     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
 7432     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
 7433     89/<- %esi 0/r32/eax
 7434     # if src doesn't exist, allocate it
 7435     {
 7436       81 7/subop/compare *esi 0/imm32
 7437       75/jump-if-!= break/disp8
 7438       (allocate Heap *Typeinfo-entry-size %esi)
 7439 #?       (write-buffered Stderr "handle at ")
 7440 #?       (print-int32-buffered Stderr %esi)
 7441 #?       (write-buffered Stderr ": ")
 7442 #?       (print-int32-buffered Stderr *esi)
 7443 #?       (write-buffered Stderr " ")
 7444 #?       (print-int32-buffered Stderr *(esi+4))
 7445 #?       (write-buffered Stderr Newline)
 7446 #?       (flush Stderr)
 7447 #?       (lookup *esi *(esi+4))
 7448 #?       (write-buffered Stderr "created typeinfo fields at ")
 7449 #?       (print-int32-buffered Stderr %esi)
 7450 #?       (write-buffered Stderr " for ")
 7451 #?       (print-int32-buffered Stderr *(ebp+8))
 7452 #?       (write-buffered Stderr Newline)
 7453 #?       (flush Stderr)
 7454     }
 7455     # *out = src
 7456     # . *edi = *src
 7457     8b/-> *esi 0/r32/eax
 7458     89/<- *edi 0/r32/eax
 7459     8b/-> *(esi+4) 0/r32/eax
 7460     89/<- *(edi+4) 0/r32/eax
 7461 $find-or-create-typeinfo-fields:end:
 7462     # . restore registers
 7463     5f/pop-to-edi
 7464     5e/pop-to-esi
 7465     58/pop-to-eax
 7466     # . epilogue
 7467     89/<- %esp 5/r32/ebp
 7468     5d/pop-to-ebp
 7469     c3/return
 7470 
 7471 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 7472     # pseudocode:
 7473     #   var line: (stream byte 512)
 7474     #   curr-index = 0
 7475     #   while true
 7476     #     clear-stream(line)
 7477     #     read-line-buffered(in, line)
 7478     #     if line->write == 0
 7479     #       abort
 7480     #     word-slice = next-mu-token(line)
 7481     #     if slice-empty?(word-slice)               # end of line
 7482     #       continue
 7483     #     if slice-equal?(word-slice, "}")
 7484     #       break
 7485     #     var v: (handle var) = parse-var-with-type(word-slice, line)
 7486     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
 7487     #     TODO: ensure that r->first is null
 7488     #     r->index = curr-index
 7489     #     curr-index++
 7490     #     r->input-var = v
 7491     #     if r->output-var == 0
 7492     #       r->output-var = new literal
 7493     #     TODO: ensure nothing else in line
 7494     # t->total-size-in-bytes = -2 (not yet initialized)
 7495     # check-input-vars(t, err, ed)
 7496     #
 7497     # . prologue
 7498     55/push-ebp
 7499     89/<- %ebp 4/r32/esp
 7500     # var curr-index: int at *(ebp-4)
 7501     68/push 0/imm32
 7502     # . save registers
 7503     50/push-eax
 7504     51/push-ecx
 7505     52/push-edx
 7506     53/push-ebx
 7507     56/push-esi
 7508     57/push-edi
 7509     # edi = t
 7510     8b/-> *(ebp+0xc) 7/r32/edi
 7511     # var line/ecx: (stream byte 512)
 7512     81 5/subop/subtract %esp 0x200/imm32
 7513     68/push 0x200/imm32/size
 7514     68/push 0/imm32/read
 7515     68/push 0/imm32/write
 7516     89/<- %ecx 4/r32/esp
 7517     # var word-slice/edx: slice
 7518     68/push 0/imm32/end
 7519     68/push 0/imm32/start
 7520     89/<- %edx 4/r32/esp
 7521     # var v/esi: (handle var)
 7522     68/push 0/imm32
 7523     68/push 0/imm32
 7524     89/<- %esi 4/r32/esp
 7525     # var r/ebx: (handle typeinfo-entry)
 7526     68/push 0/imm32
 7527     68/push 0/imm32
 7528     89/<- %ebx 4/r32/esp
 7529     {
 7530 $populate-mu-type:line-loop:
 7531       (clear-stream %ecx)
 7532       (read-line-buffered *(ebp+8) %ecx)
 7533       # if (line->write == 0) abort
 7534       81 7/subop/compare *ecx 0/imm32
 7535       0f 84/jump-if-= $populate-mu-type:abort/disp32
 7536 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 7542       (next-mu-token %ecx %edx)
 7543       # if slice-empty?(word-slice) continue
 7544       (slice-empty? %edx)  # => eax
 7545       3d/compare-eax-and 0/imm32
 7546       0f 85/jump-if-!= loop/disp32
 7547       # if slice-equal?(word-slice, "}") break
 7548       (slice-equal? %edx "}")
 7549       3d/compare-eax-and 0/imm32
 7550       0f 85/jump-if-!= break/disp32
 7551 $populate-mu-type:parse-element:
 7552       # v = parse-var-with-type(word-slice, first-line)
 7553       # must do this first to strip the trailing ':' from word-slice before
 7554       # using it in find-or-create-typeinfo-fields below
 7555       # TODO: clean up that mutation in parse-var-with-type
 7556       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
 7557       # var tmp/ecx
 7558       51/push-ecx
 7559 $populate-mu-type:create-typeinfo-fields:
 7560       # var r/ebx: (handle typeinfo-entry)
 7561       (find-or-create-typeinfo-fields %edi %edx %ebx)
 7562       # r->index = curr-index
 7563       (lookup *ebx *(ebx+4))  # => eax
 7564       8b/-> *(ebp-4) 1/r32/ecx
 7565 #?       (write-buffered Stderr "saving index ")
 7566 #?       (print-int32-buffered Stderr %ecx)
 7567 #?       (write-buffered Stderr " at ")
 7568 #?       (print-int32-buffered Stderr %edi)
 7569 #?       (write-buffered Stderr Newline)
 7570 #?       (flush Stderr)
 7571       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
 7572       # ++curr-index
 7573       ff 0/subop/increment *(ebp-4)
 7574 $populate-mu-type:set-input-type:
 7575       # r->input-var = v
 7576       8b/-> *esi 1/r32/ecx
 7577       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
 7578       8b/-> *(esi+4) 1/r32/ecx
 7579       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
 7580       59/pop-to-ecx
 7581       {
 7582 $populate-mu-type:create-output-type:
 7583         # if (r->output-var == 0) create a new var with some placeholder data
 7584         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
 7585         75/jump-if-!= break/disp8
 7586         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 7587         (new-literal Heap %edx %eax)
 7588       }
 7589       e9/jump loop/disp32
 7590     }
 7591 $populate-mu-type:invalidate-total-size-in-bytes:
 7592     # Offsets and total size may not be accurate here since we may not yet
 7593     # have encountered the element types.
 7594     # We'll recompute them separately after parsing the entire program.
 7595     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
 7596 $populate-mu-type:validate:
 7597     (check-input-vars *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 7598 $populate-mu-type:end:
 7599     # . reclaim locals
 7600     81 0/subop/add %esp 0x224/imm32
 7601     # . restore registers
 7602     5f/pop-to-edi
 7603     5e/pop-to-esi
 7604     5b/pop-to-ebx
 7605     5a/pop-to-edx
 7606     59/pop-to-ecx
 7607     58/pop-to-eax
 7608     # reclaim curr-index
 7609     81 0/subop/add %esp 4/imm32
 7610     # . epilogue
 7611     89/<- %esp 5/r32/ebp
 7612     5d/pop-to-ebp
 7613     c3/return
 7614 
 7615 $populate-mu-type:abort:
 7616     # error("unexpected top-level command: " word-slice "\n")
 7617     (write-buffered *(ebp+0x10) "incomplete type definition '")
 7618     (type-name *edi)  # Typeinfo-id => eax
 7619     (write-buffered *(ebp+0x10) %eax)
 7620     (write-buffered *(ebp+0x10) "\n")
 7621     (flush *(ebp+0x10))
 7622     (stop *(ebp+0x14) 1)
 7623     # never gets here
 7624 
 7625 check-input-vars:  # t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 7626     # . prologue
 7627     55/push-ebp
 7628     89/<- %ebp 4/r32/esp
 7629     # . save registers
 7630     50/push-eax
 7631     51/push-ecx
 7632     52/push-edx
 7633     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(t->fields)
 7634     8b/-> *(ebp+8) 0/r32/eax
 7635     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
 7636     89/<- %ecx 0/r32/eax
 7637     # var table-size/edx: int = table->write
 7638     8b/-> *ecx 2/r32/edx  # stream-write
 7639     # var curr/ecx: (addr table_row) = table->data
 7640     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7641     # var max/edx: (addr table_row) = table->data + table->write
 7642     8d/copy-address *(ecx+edx) 2/r32/edx
 7643     {
 7644 $check-input-vars:loop:
 7645       # if (curr >= max) break
 7646       39/compare %ecx 2/r32/edx
 7647       73/jump-if-addr>= break/disp8
 7648       (lookup *ecx *(ecx+4))  # => eax
 7649       # var t2/eax: (addr typeinfo-entry) = lookup(curr->value)
 7650       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7651       # if (t2->input-var == null) raise an error
 7652       8b/-> *eax 0/r32/eax  # Typeinfo-entry-input-var
 7653       3d/compare-eax-and 0/imm32/null
 7654       0f 84/jump-if-= $check-input-vars:abort/disp32
 7655       # curr += row-size
 7656       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 7657       #
 7658       eb/jump loop/disp8
 7659     }
 7660 $check-input-vars:end:
 7661     # . restore registers
 7662     5a/pop-to-edx
 7663     59/pop-to-ecx
 7664     58/pop-to-eax
 7665     # . epilogue
 7666     89/<- %esp 5/r32/ebp
 7667     5d/pop-to-ebp
 7668     c3/return
 7669 
 7670 $check-input-vars:abort:
 7671     # error("type " type " has no member called '" curr->name "'\n")
 7672     (write-buffered *(ebp+0xc) "type '")
 7673     # . var tmp/edx: int = t->id << 2
 7674     8b/-> *(ebp+8) 0/r32/eax
 7675     8b/-> *eax 2/r32/edx  # Typeinfo-id
 7676     c1/shift 4/subop/left %edx 2/imm8
 7677     # . var a/edx: (addr array byte) = Type-id->data[tmp]
 7678     b8/copy-to-eax Type-id/imm32
 7679     8b/-> *(eax+edx+0xc) 2/r32/edx
 7680     (write-buffered *(ebp+0xc) %edx)
 7681     (write-buffered *(ebp+0xc) "' has no member called '")
 7682     (lookup *ecx *(ecx+4))  # => eax
 7683     (write-buffered *(ebp+0xc) %eax)
 7684     (write-buffered *(ebp+0xc) "'\n")
 7685     (flush *(ebp+0xc))
 7686     (stop *(ebp+0x10) 1)
 7687     # never gets here
 7688 
 7689 type-name:  # index: int -> result/eax: (addr array byte)
 7690     # . prologue
 7691     55/push-ebp
 7692     89/<- %ebp 4/r32/esp
 7693     #
 7694     (index Type-id *(ebp+8))
 7695 $type-name:end:
 7696     # . epilogue
 7697     89/<- %esp 5/r32/ebp
 7698     5d/pop-to-ebp
 7699     c3/return
 7700 
 7701 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
 7702     # . prologue
 7703     55/push-ebp
 7704     89/<- %ebp 4/r32/esp
 7705     # . save registers
 7706     56/push-esi
 7707     # TODO: bounds-check index
 7708     # esi = arr
 7709     8b/-> *(ebp+8) 6/r32/esi
 7710     # eax = index
 7711     8b/-> *(ebp+0xc) 0/r32/eax
 7712     # eax = *(arr + 12 + index)
 7713     8b/-> *(esi+eax+0xc) 0/r32/eax
 7714 $index:end:
 7715     # . restore registers
 7716     5e/pop-to-esi
 7717     # . epilogue
 7718     89/<- %esp 5/r32/ebp
 7719     5d/pop-to-ebp
 7720     c3/return
 7721 
 7722 #######################################################
 7723 # Compute type sizes
 7724 #######################################################
 7725 
 7726 # Compute the sizes of all user-defined types.
 7727 # We'll need the sizes of their elements, which may be other user-defined
 7728 # types, which we will compute as needed.
 7729 
 7730 # Initially, all user-defined types have their sizes set to -2 (invalid)
 7731 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
 7732     # . prologue
 7733     55/push-ebp
 7734     89/<- %ebp 4/r32/esp
 7735 $populate-mu-type-sizes:total-sizes:
 7736     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 7737     (lookup *_Program-types *_Program-types->payload)  # => eax
 7738     {
 7739       # if (curr == null) break
 7740       3d/compare-eax-and 0/imm32/null
 7741       74/jump-if-= break/disp8
 7742       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
 7743       # curr = lookup(curr->next)
 7744       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7745       eb/jump loop/disp8
 7746     }
 7747 $populate-mu-type-sizes:offsets:
 7748     # curr = *Program->types
 7749     (lookup *_Program-types *_Program-types->payload)  # => eax
 7750     {
 7751       # if (curr == null) break
 7752       3d/compare-eax-and 0/imm32/null
 7753       74/jump-if-= break/disp8
 7754       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
 7755       # curr = curr->next
 7756       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 7757       eb/jump loop/disp8
 7758     }
 7759 $populate-mu-type-sizes:end:
 7760     # . epilogue
 7761     89/<- %esp 5/r32/ebp
 7762     5d/pop-to-ebp
 7763     c3/return
 7764 
 7765 # compute sizes of all fields, recursing as necessary
 7766 # sum up all their sizes to arrive at total size
 7767 # fields may be out of order, but that doesn't affect the answer
 7768 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 7769     # . prologue
 7770     55/push-ebp
 7771     89/<- %ebp 4/r32/esp
 7772     # . save registers
 7773     50/push-eax
 7774     51/push-ecx
 7775     52/push-edx
 7776     56/push-esi
 7777     57/push-edi
 7778     # esi = T
 7779     8b/-> *(ebp+8) 6/r32/esi
 7780     # if T is already computed, return
 7781     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
 7782     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
 7783     # if T is being computed, abort
 7784     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7785     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
 7786     # tag T (-2 to -1) to avoid infinite recursion
 7787     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
 7788     # var total-size/edi: int = 0
 7789     bf/copy-to-edi 0/imm32
 7790     # - for every field, if it's a user-defined type, compute its size
 7791     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 7792     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 7793     89/<- %ecx 0/r32/eax
 7794     # var table-size/edx: int = table->write
 7795     8b/-> *ecx 2/r32/edx  # stream-write
 7796     # var curr/ecx: (addr table_row) = table->data
 7797     8d/copy-address *(ecx+0xc) 1/r32/ecx
 7798     # var max/edx: (addr table_row) = table->data + table->write
 7799     8d/copy-address *(ecx+edx) 2/r32/edx
 7800     {
 7801 $populate-mu-type-sizes-in-type:loop:
 7802       # if (curr >= max) break
 7803       39/compare %ecx 2/r32/edx
 7804       73/jump-if-addr>= break/disp8
 7805       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
 7806       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7807       # compute size of t->input-var
 7808       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7809       (compute-size-of-var %eax)  # => eax
 7810       # result += eax
 7811       01/add-to %edi 0/r32/eax
 7812       # curr += row-size
 7813       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 7814       #
 7815       eb/jump loop/disp8
 7816     }
 7817     # - save result
 7818     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
 7819 $populate-mu-type-sizes-in-type:end:
 7820     # . restore registers
 7821     5f/pop-to-edi
 7822     5e/pop-to-esi
 7823     5a/pop-to-edx
 7824     59/pop-to-ecx
 7825     58/pop-to-eax
 7826     # . epilogue
 7827     89/<- %esp 5/r32/ebp
 7828     5d/pop-to-ebp
 7829     c3/return
 7830 
 7831 $populate-mu-type-sizes-in-type:abort:
 7832     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
 7833     (flush *(ebp+0xc))
 7834     (stop *(ebp+0x10) 1)
 7835     # never gets here
 7836 
 7837 # Analogous to size-of, except we need to compute what size-of can just read
 7838 # off the right data structures.
 7839 compute-size-of-var:  # in: (addr var) -> result/eax: int
 7840     # . prologue
 7841     55/push-ebp
 7842     89/<- %ebp 4/r32/esp
 7843     # . push registers
 7844     51/push-ecx
 7845     # var t/ecx: (addr tree type-id) = lookup(v->type)
 7846     8b/-> *(ebp+8) 1/r32/ecx
 7847     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 7848     89/<- %ecx 0/r32/eax
 7849     # if (t->is-atom == false) t = lookup(t->left)
 7850     {
 7851       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 7852       75/jump-if-!= break/disp8
 7853       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 7854       89/<- %ecx 0/r32/eax
 7855     }
 7856     # TODO: ensure t is an atom
 7857     (compute-size-of-type-id *(ecx+4))  # Tree-value => eax
 7858 $compute-size-of-var:end:
 7859     # . restore registers
 7860     59/pop-to-ecx
 7861     # . epilogue
 7862     89/<- %esp 5/r32/ebp
 7863     5d/pop-to-ebp
 7864     c3/return
 7865 
 7866 compute-size-of-type-id:  # t: type-id -> result/eax: int
 7867     # . prologue
 7868     55/push-ebp
 7869     89/<- %ebp 4/r32/esp
 7870     # . save registers
 7871     51/push-ecx
 7872     # var out/ecx: (handle typeinfo)
 7873     68/push 0/imm32
 7874     68/push 0/imm32
 7875     89/<- %ecx 4/r32/esp
 7876     # eax = t
 7877     8b/-> *(ebp+8) 0/r32/eax
 7878     # if v is a literal, return 0
 7879     3d/compare-eax-and 0/imm32/literal
 7880     74/jump-if-= $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
 7881     # if v is a byte, return 1
 7882     {
 7883       3d/compare-eax-and 8/imm32/byte
 7884       75/jump-if-!= break/disp8
 7885       b8/copy-to-eax 1/imm32
 7886       eb/jump $compute-size-of-type-id:end/disp8
 7887     }
 7888     # if v has a user-defined type, compute its size
 7889     # TODO: support non-atom type
 7890     (find-typeinfo %eax %ecx)
 7891     {
 7892       81 7/subop/compare *ecx 0/imm32
 7893       74/jump-if-= break/disp8
 7894 $compute-size-of-type-id:user-defined:
 7895       (populate-mu-type-sizes %eax)
 7896       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 7897       eb/jump $compute-size-of-type-id:end/disp8
 7898     }
 7899     # otherwise return the word size
 7900     b8/copy-to-eax 4/imm32
 7901 $compute-size-of-type-id:end:
 7902     # . reclaim locals
 7903     81 0/subop/add %esp 8/imm32
 7904     # . restore registers
 7905     59/pop-to-ecx
 7906     # . epilogue
 7907     89/<- %esp 5/r32/ebp
 7908     5d/pop-to-ebp
 7909     c3/return
 7910 
 7911 # at this point we have total sizes for all user-defined types
 7912 # compute offsets for each element
 7913 # complication: fields may be out of order
 7914 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
 7915     # . prologue
 7916     55/push-ebp
 7917     89/<- %ebp 4/r32/esp
 7918     # . save registers
 7919     50/push-eax
 7920     51/push-ecx
 7921     52/push-edx
 7922     53/push-ebx
 7923     56/push-esi
 7924     57/push-edi
 7925 #?     (dump-typeinfos "aaa\n")
 7926     # var curr-offset/edi: int = 0
 7927     bf/copy-to-edi 0/imm32
 7928     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
 7929     8b/-> *(ebp+8) 1/r32/ecx
 7930     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
 7931     89/<- %ecx 0/r32/eax
 7932     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
 7933     8b/-> *ecx 2/r32/edx  # stream-write
 7934     c1 5/subop/shift-right-logical  %edx 4/imm8
 7935     # var i/ebx: int = 0
 7936     bb/copy-to-ebx 0/imm32
 7937     {
 7938 $populate-mu-type-offsets:loop:
 7939       39/compare %ebx 2/r32/edx
 7940       7d/jump-if->= break/disp8
 7941 #?       (write-buffered Stderr "looking up index ")
 7942 #?       (print-int32-buffered Stderr %ebx)
 7943 #?       (write-buffered Stderr " in ")
 7944 #?       (print-int32-buffered Stderr *(ebp+8))
 7945 #?       (write-buffered Stderr Newline)
 7946 #?       (flush Stderr)
 7947       # var v/esi: (addr typeinfo-entry)
 7948       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
 7949       89/<- %esi 0/r32/eax
 7950       # v->output-var->offset = curr-offset
 7951       # . eax: (addr var)
 7952       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
 7953       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
 7954       # curr-offset += size-of(v->input-var)
 7955       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
 7956       (size-of %eax)  # => eax
 7957       01/add-to %edi 0/r32/eax
 7958       # ++i
 7959       43/increment-ebx
 7960       eb/jump loop/disp8
 7961     }
 7962 $populate-mu-type-offsets:end:
 7963     # . restore registers
 7964     5f/pop-to-edi
 7965     5e/pop-to-esi
 7966     5b/pop-to-ebx
 7967     5a/pop-to-edx
 7968     59/pop-to-ecx
 7969     58/pop-to-eax
 7970     # . epilogue
 7971     89/<- %esp 5/r32/ebp
 7972     5d/pop-to-ebp
 7973     c3/return
 7974 
 7975 locate-typeinfo-entry-with-index:  # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: (addr typeinfo-entry)
 7976     # . prologue
 7977     55/push-ebp
 7978     89/<- %ebp 4/r32/esp
 7979     # . save registers
 7980     51/push-ecx
 7981     52/push-edx
 7982     53/push-ebx
 7983     56/push-esi
 7984     57/push-edi
 7985     # esi = table
 7986     8b/-> *(ebp+8) 6/r32/esi
 7987     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
 7988     8d/copy-address *(esi+0xc) 1/r32/ecx
 7989     # var max/edx: (addr byte) = &table->data[table->write]
 7990     8b/-> *esi 2/r32/edx
 7991     8d/copy-address *(ecx+edx) 2/r32/edx
 7992     {
 7993 $locate-typeinfo-entry-with-index:loop:
 7994       39/compare %ecx 2/r32/edx
 7995       73/jump-if-addr>= $locate-typeinfo-entry-with-index:abort/disp8
 7996       # var v/eax: (addr typeinfo-entry)
 7997       (lookup *(ecx+8) *(ecx+0xc))  # => eax
 7998       # if (v->index == idx) return v
 7999       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
 8000 #?       (write-buffered Stderr "comparing ")
 8001 #?       (print-int32-buffered Stderr %ebx)
 8002 #?       (write-buffered Stderr " and ")
 8003 #?       (print-int32-buffered Stderr *(ebp+0xc))
 8004 #?       (write-buffered Stderr Newline)
 8005 #?       (flush Stderr)
 8006       39/compare *(ebp+0xc) 3/r32/ebx
 8007       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
 8008       # curr += Typeinfo-entry-size
 8009       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
 8010       #
 8011       eb/jump loop/disp8
 8012     }
 8013     # return 0
 8014     b8/copy-to-eax 0/imm32
 8015 $locate-typeinfo-entry-with-index:end:
 8016 #?     (write-buffered Stderr "returning ")
 8017 #?     (print-int32-buffered Stderr %eax)
 8018 #?     (write-buffered Stderr Newline)
 8019 #?     (flush Stderr)
 8020     # . restore registers
 8021     5f/pop-to-edi
 8022     5e/pop-to-esi
 8023     5b/pop-to-ebx
 8024     5a/pop-to-edx
 8025     59/pop-to-ecx
 8026     # . epilogue
 8027     89/<- %esp 5/r32/ebp
 8028     5d/pop-to-ebp
 8029     c3/return
 8030 
 8031 $locate-typeinfo-entry-with-index:abort:
 8032     (write-buffered *(ebp+0x10) "overflowing typeinfo-entry->index ")
 8033     (print-int32-buffered *(ebp+0x10) %ecx)
 8034     (write-buffered *(ebp+0x10) "\n")
 8035     (flush *(ebp+0x10))
 8036     (stop *(ebp+0x14) 1)
 8037     # never gets here
 8038 
 8039 dump-typeinfos:  # hdr: (addr array byte)
 8040     # . prologue
 8041     55/push-ebp
 8042     89/<- %ebp 4/r32/esp
 8043     # . save registers
 8044     50/push-eax
 8045     #
 8046     (write-buffered Stderr *(ebp+8))
 8047     (flush Stderr)
 8048     # var curr/eax: (addr typeinfo) = lookup(Program->types)
 8049     (lookup *_Program-types *_Program-types->payload)  # => eax
 8050     {
 8051       # if (curr == null) break
 8052       3d/compare-eax-and 0/imm32
 8053       74/jump-if-= break/disp8
 8054       (write-buffered Stderr "---\n")
 8055       (flush Stderr)
 8056       (dump-typeinfo %eax)
 8057       # curr = lookup(curr->next)
 8058       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
 8059       eb/jump loop/disp8
 8060     }
 8061 $dump-typeinfos:end:
 8062     # . restore registers
 8063     58/pop-to-eax
 8064     # . epilogue
 8065     89/<- %esp 5/r32/ebp
 8066     5d/pop-to-ebp
 8067     c3/return
 8068 
 8069 dump-typeinfo:  # in: (addr typeinfo)
 8070     # . prologue
 8071     55/push-ebp
 8072     89/<- %ebp 4/r32/esp
 8073     # . save registers
 8074     50/push-eax
 8075     51/push-ecx
 8076     52/push-edx
 8077     53/push-ebx
 8078     56/push-esi
 8079     57/push-edi
 8080     # esi = in
 8081     8b/-> *(ebp+8) 6/r32/esi
 8082     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
 8083     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
 8084     89/<- %ecx 0/r32/eax
 8085     (write-buffered Stderr "id:")
 8086     (print-int32-buffered Stderr *esi)
 8087     (write-buffered Stderr "\n")
 8088     (write-buffered Stderr "fields @ ")
 8089     (print-int32-buffered Stderr %ecx)
 8090     (write-buffered Stderr Newline)
 8091     (flush Stderr)
 8092     (write-buffered Stderr "  write: ")
 8093     (print-int32-buffered Stderr *ecx)
 8094     (write-buffered Stderr Newline)
 8095     (flush Stderr)
 8096     (write-buffered Stderr "  read: ")
 8097     (print-int32-buffered Stderr *(ecx+4))
 8098     (write-buffered Stderr Newline)
 8099     (flush Stderr)
 8100     (write-buffered Stderr "  size: ")
 8101     (print-int32-buffered Stderr *(ecx+8))
 8102     (write-buffered Stderr Newline)
 8103     (flush Stderr)
 8104     # var table-size/edx: int = table->write
 8105     8b/-> *ecx 2/r32/edx  # stream-write
 8106     # var curr/ecx: (addr table_row) = table->data
 8107     8d/copy-address *(ecx+0xc) 1/r32/ecx
 8108     # var max/edx: (addr table_row) = table->data + table->write
 8109     8d/copy-address *(ecx+edx) 2/r32/edx
 8110     {
 8111 $dump-typeinfo:loop:
 8112       # if (curr >= max) break
 8113       39/compare %ecx 2/r32/edx
 8114       0f 83/jump-if-addr>= break/disp32
 8115       (write-buffered Stderr "  row:\n")
 8116       (write-buffered Stderr "    key: ")
 8117       (print-int32-buffered Stderr *ecx)
 8118       (write-buffered Stderr ",")
 8119       (print-int32-buffered Stderr *(ecx+4))
 8120       (write-buffered Stderr " = '")
 8121       (lookup *ecx *(ecx+4))
 8122       (write-buffered Stderr %eax)
 8123       (write-buffered Stderr "' @ ")
 8124       (print-int32-buffered Stderr %eax)
 8125       (write-buffered Stderr Newline)
 8126       (flush Stderr)
 8127       (write-buffered Stderr "    value: ")
 8128       (print-int32-buffered Stderr *(ecx+8))
 8129       (write-buffered Stderr ",")
 8130       (print-int32-buffered Stderr *(ecx+0xc))
 8131       (write-buffered Stderr " = typeinfo-entry@")
 8132       (lookup *(ecx+8) *(ecx+0xc))
 8133       (print-int32-buffered Stderr %eax)
 8134       (write-buffered Stderr Newline)
 8135       (flush Stderr)
 8136       (write-buffered Stderr "        input var@")
 8137       (print-int32-buffered Stderr *eax)
 8138       (write-buffered Stderr ",")
 8139       (print-int32-buffered Stderr *(eax+4))
 8140       (write-buffered Stderr "->")
 8141       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var
 8142       (print-int32-buffered Stderr %eax)
 8143       {
 8144         3d/compare-eax-and 0/imm32
 8145         74/jump-if-= break/disp8
 8146         (write-buffered Stderr " ")
 8147         # TODO
 8148       }
 8149       (write-buffered Stderr Newline)
 8150       (flush Stderr)
 8151       (lookup *(ecx+8) *(ecx+0xc))
 8152       (write-buffered Stderr "        index: ")
 8153       (print-int32-buffered Stderr *(eax+8))
 8154       (write-buffered Stderr Newline)
 8155       (flush Stderr)
 8156       (write-buffered Stderr "        output var@")
 8157       (print-int32-buffered Stderr *(eax+0xc))
 8158       (write-buffered Stderr ",")
 8159       (print-int32-buffered Stderr *(eax+0x10))
 8160       (write-buffered Stderr "->")
 8161       (lookup *(eax+0xc) *(eax+0x10))  # Typeinfo-entry-output-var
 8162       (print-int32-buffered Stderr %eax)
 8163       (write-buffered Stderr Newline)
 8164       (flush Stderr)
 8165       {
 8166         3d/compare-eax-and 0/imm32
 8167         0f 84/jump-if-= break/disp32
 8168         (write-buffered Stderr "          name: ")
 8169         89/<- %ebx 0/r32/eax
 8170         (print-int32-buffered Stderr *ebx)  # Var-name
 8171         (write-buffered Stderr ",")
 8172         (print-int32-buffered Stderr *(ebx+4))  # Var-name
 8173         (write-buffered Stderr "->")
 8174         (lookup *ebx *(ebx+4))  # Var-name
 8175         (print-int32-buffered Stderr %eax)
 8176         {
 8177           3d/compare-eax-and 0/imm32
 8178           74/jump-if-= break/disp8
 8179           (write-buffered Stderr Space)
 8180           (write-buffered Stderr %eax)
 8181         }
 8182         (write-buffered Stderr Newline)
 8183         (flush Stderr)
 8184         (write-buffered Stderr "          block depth: ")
 8185         (print-int32-buffered Stderr *(ebx+0x10))  # Var-block-depth
 8186         (write-buffered Stderr Newline)
 8187         (flush Stderr)
 8188         (write-buffered Stderr "          stack offset: ")
 8189         (print-int32-buffered Stderr *(ebx+0x14))  # Var-offset
 8190         (write-buffered Stderr Newline)
 8191         (flush Stderr)
 8192         (write-buffered Stderr "          reg: ")
 8193         (print-int32-buffered Stderr *(ebx+0x18))  # Var-register
 8194         (write-buffered Stderr ",")
 8195         (print-int32-buffered Stderr *(ebx+0x1c))  # Var-register
 8196         (write-buffered Stderr "->")
 8197         (flush Stderr)
 8198         (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
 8199         (print-int32-buffered Stderr %eax)
 8200         {
 8201           3d/compare-eax-and 0/imm32
 8202           74/jump-if-= break/disp8
 8203           (write-buffered Stderr Space)
 8204           (write-buffered Stderr %eax)
 8205         }
 8206         (write-buffered Stderr Newline)
 8207         (flush Stderr)
 8208       }
 8209       (flush Stderr)
 8210       # curr += row-size
 8211       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
 8212       #
 8213       e9/jump loop/disp32
 8214     }
 8215 $dump-typeinfo:end:
 8216     # . restore registers
 8217     5f/pop-to-edi
 8218     5e/pop-to-esi
 8219     5b/pop-to-ebx
 8220     5a/pop-to-edx
 8221     59/pop-to-ecx
 8222     58/pop-to-eax
 8223     # . epilogue
 8224     89/<- %esp 5/r32/ebp
 8225     5d/pop-to-ebp
 8226     c3/return
 8227 
 8228 #######################################################
 8229 # Type-checking
 8230 #######################################################
 8231 
 8232 check-mu-types:
 8233     # . prologue
 8234     55/push-ebp
 8235     89/<- %ebp 4/r32/esp
 8236     #
 8237 $check-mu-types:end:
 8238     # . epilogue
 8239     89/<- %esp 5/r32/ebp
 8240     5d/pop-to-ebp
 8241     c3/return
 8242 
 8243 size-of:  # v: (addr var) -> result/eax: int
 8244     # . prologue
 8245     55/push-ebp
 8246     89/<- %ebp 4/r32/esp
 8247     # . save registers
 8248     51/push-ecx
 8249     # var t/ecx: (addr tree type-id) = lookup(v->type)
 8250     8b/-> *(ebp+8) 1/r32/ecx
 8251 #?     (write-buffered Stderr "size-of ")
 8252 #?     (print-int32-buffered Stderr %ecx)
 8253 #?     (write-buffered Stderr Newline)
 8254 #?     (write-buffered Stderr "type allocid: ")
 8255 #?     (print-int32-buffered Stderr *(ecx+8))
 8256 #?     (write-buffered Stderr Newline)
 8257 #?     (flush Stderr)
 8258     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8259     89/<- %ecx 0/r32/eax
 8260     # if is-mu-array?(t) return size-of-array(t)
 8261     {
 8262       (is-mu-array? %ecx)  # => eax
 8263       3d/compare-eax-and 0/imm32/false
 8264       74/jump-if-= break/disp8
 8265       (size-of-array %ecx)  # => eax
 8266       eb/jump $size-of:end/disp8
 8267     }
 8268     # if (!t->is-atom?) t = lookup(t->left)
 8269     {
 8270       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8271       75/jump-if-!= break/disp8
 8272       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8273       89/<- %ecx 0/r32/eax
 8274     }
 8275     # TODO: assert t->is-atom?
 8276     (size-of-type-id *(ecx+4))  # Tree-value => eax
 8277 $size-of:end:
 8278     # . restore registers
 8279     59/pop-to-ecx
 8280     # . epilogue
 8281     89/<- %esp 5/r32/ebp
 8282     5d/pop-to-ebp
 8283     c3/return
 8284 
 8285 size-of-deref:  # v: (addr var) -> result/eax: int
 8286     # . prologue
 8287     55/push-ebp
 8288     89/<- %ebp 4/r32/esp
 8289     # . save registers
 8290     51/push-ecx
 8291     # var t/ecx: (addr tree type-id) = lookup(v->type)
 8292     8b/-> *(ebp+8) 1/r32/ecx
 8293     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8294     89/<- %ecx 0/r32/eax
 8295     # TODO: assert(t is an addr)
 8296     # t = lookup(t->right)
 8297     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8298     89/<- %ecx 0/r32/eax
 8299     # if is-mu-array?(t) return size-of-array(t)
 8300     {
 8301       (is-mu-array? %ecx)  # => eax
 8302       3d/compare-eax-and 0/imm32/false
 8303       74/jump-if-= break/disp8
 8304       (size-of-array %ecx)  # => eax
 8305       eb/jump $size-of:end/disp8
 8306     }
 8307     # if (!t->is-atom?) t = lookup(t->left)
 8308     {
 8309       81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8310       75/jump-if-!= break/disp8
 8311       (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8312       89/<- %ecx 0/r32/eax
 8313     }
 8314     # TODO: assert t->is-atom?
 8315     (size-of-type-id *(ecx+4))  # Tree-value => eax
 8316 $size-of-deref:end:
 8317     # . restore registers
 8318     59/pop-to-ecx
 8319     # . epilogue
 8320     89/<- %esp 5/r32/ebp
 8321     5d/pop-to-ebp
 8322     c3/return
 8323 
 8324 is-mu-array?:  # t: (addr tree type-id) -> result/eax: boolean
 8325     # . prologue
 8326     55/push-ebp
 8327     89/<- %ebp 4/r32/esp
 8328     # . save registers
 8329     51/push-ecx
 8330     # ecx = t
 8331     8b/-> *(ebp+8) 1/r32/ecx
 8332     # if t->is-atom?, return false
 8333     81 7/subop/compare *ecx 0/imm32/false  # Tree-is-atom
 8334     75/jump-if-!= $is-mu-array?:return-false/disp8
 8335     # if !t->left->is-atom?, return false
 8336     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8337     81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
 8338     74/jump-if-= $is-mu-array?:return-false/disp8
 8339     # return t->left->value == array
 8340     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Tree-value
 8341     0f 94/set-if-= %al
 8342     81 4/subop/and %eax 0xff/imm32
 8343     eb/jump $is-mu-array?:end/disp8
 8344 $is-mu-array?:return-false:
 8345     b8/copy-to-eax 0/imm32/false
 8346 $is-mu-array?:end:
 8347     # . restore registers
 8348     59/pop-to-ecx
 8349     # . epilogue
 8350     89/<- %esp 5/r32/ebp
 8351     5d/pop-to-ebp
 8352     c3/return
 8353 
 8354 size-of-array:  # a: (addr tree type-id) -> result/eax: int
 8355     # . prologue
 8356     55/push-ebp
 8357     89/<- %ebp 4/r32/esp
 8358     # . save registers
 8359     51/push-ecx
 8360     52/push-edx
 8361     #
 8362     8b/-> *(ebp+8) 1/r32/ecx
 8363     # TODO: assert that a->left is 'array'
 8364     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8365     89/<- %ecx 0/r32/eax
 8366     # var elem-type/edx: type-id = a->right->left->value
 8367     (lookup *(ecx+4) *(ecx+8))  # Tree-left Tree-left => eax
 8368     8b/-> *(eax+4) 2/r32/edx  # Tree-value
 8369     # var array-size/ecx: int = a->right->right->left->value
 8370     (lookup *(ecx+0xc) *(ecx+0x10))  # Tree-right Tree-right => eax
 8371     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
 8372     8b/-> *(eax+4) 1/r32/ecx  # Tree-value
 8373     # return array-size * size-of(elem-type)
 8374     (size-of-type-id %edx)  # => eax
 8375     f7 4/subop/multiply-into-eax %ecx
 8376     05/add-to-eax 4/imm32  # for array size
 8377 $size-of-array:end:
 8378     # . restore registers
 8379     5a/pop-to-edx
 8380     59/pop-to-ecx
 8381     # . epilogue
 8382     89/<- %esp 5/r32/ebp
 8383     5d/pop-to-ebp
 8384     c3/return
 8385 
 8386 size-of-type-id:  # t: type-id -> result/eax: int
 8387     # . prologue
 8388     55/push-ebp
 8389     89/<- %ebp 4/r32/esp
 8390     # . save registers
 8391     51/push-ecx
 8392     # var out/ecx: (handle typeinfo)
 8393     68/push 0/imm32
 8394     68/push 0/imm32
 8395     89/<- %ecx 4/r32/esp
 8396     # eax = t
 8397     8b/-> *(ebp+8) 0/r32/eax
 8398     # if t is a literal, return 0
 8399     3d/compare-eax-and 0/imm32
 8400     74/jump-if-= $size-of-type-id:end/disp8  # eax changes type from type-id to int
 8401     # if t is a handle, return 8
 8402     3d/compare-eax-and 4/imm32/handle
 8403     {
 8404       75/jump-if-!= break/disp8
 8405       b8/copy-to-eax 8/imm32
 8406       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
 8407     }
 8408     # if t is a user-defined type, return its size
 8409     # TODO: support non-atom type
 8410     (find-typeinfo %eax %ecx)
 8411     {
 8412       81 7/subop/compare *ecx 0/imm32
 8413       74/jump-if-= break/disp8
 8414 $size-of-type-id:user-defined:
 8415       (lookup *ecx *(ecx+4))  # => eax
 8416       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
 8417       eb/jump $size-of-type-id:end/disp8
 8418     }
 8419     # otherwise return the word size
 8420     b8/copy-to-eax 4/imm32
 8421 $size-of-type-id:end:
 8422     # . reclaim locals
 8423     81 0/subop/add %esp 8/imm32
 8424     # . restore registers
 8425     59/pop-to-ecx
 8426     # . epilogue
 8427     89/<- %esp 5/r32/ebp
 8428     5d/pop-to-ebp
 8429     c3/return
 8430 
 8431 type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
 8432     # . prologue
 8433     55/push-ebp
 8434     89/<- %ebp 4/r32/esp
 8435     # . save registers
 8436     51/push-ecx
 8437     52/push-edx
 8438     # ecx = a
 8439     8b/-> *(ebp+8) 1/r32/ecx
 8440     # edx = b
 8441     8b/-> *(ebp+0xc) 2/r32/edx
 8442     # if (a == b) return true
 8443     8b/-> %ecx 0/r32/eax  # Var-type
 8444     39/compare %edx 0/r32/eax  # Var-type
 8445     b8/copy-to-eax 1/imm32/true
 8446     74/jump-if-= $type-equal?:end/disp8
 8447     # if (a < MAX_TYPE_ID) return false
 8448     81 7/subop/compare %ecx 0x10000/imm32
 8449     b8/copy-to-eax 0/imm32/false
 8450     72/jump-if-addr< $type-equal?:end/disp8
 8451     # if (b < MAX_TYPE_ID) return false
 8452     81 7/subop/compare %edx 0x10000/imm32
 8453     b8/copy-to-eax 0/imm32/false
 8454     72/jump-if-addr< $type-equal?:end/disp8
 8455     # if (!type-equal?(a->left, b->left)) return false
 8456     (type-equal? *(ecx+4) *(edx+4))  # Tree-left, Tree-left => eax
 8457     3d/compare-eax-and 0/imm32/false
 8458     74/jump-if-= $type-equal?:end/disp8
 8459     # return type-equal?(a->right, b->right)
 8460     (type-equal? *(ecx+8) *(edx+8))  # Tree-right, Tree-right => eax
 8461 $type-equal?:end:
 8462     # . restore registers
 8463     5a/pop-to-edx
 8464     59/pop-to-ecx
 8465     # . epilogue
 8466     89/<- %esp 5/r32/ebp
 8467     5d/pop-to-ebp
 8468     c3/return
 8469 
 8470 #######################################################
 8471 # Code-generation
 8472 #######################################################
 8473 
 8474 == data
 8475 
 8476 Curr-block-depth:  # (addr int)
 8477     0/imm32
 8478 Curr-local-stack-offset:  # (addr int)
 8479     0/imm32
 8480 
 8481 == code
 8482 
 8483 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 8484     # . prologue
 8485     55/push-ebp
 8486     89/<- %ebp 4/r32/esp
 8487     # . save registers
 8488     50/push-eax
 8489     # var curr/eax: (addr function) = *Program->functions
 8490     (lookup *_Program-functions *_Program-functions->payload)  # => eax
 8491     {
 8492       # if (curr == null) break
 8493       3d/compare-eax-and 0/imm32
 8494       0f 84/jump-if-= break/disp32
 8495       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
 8496       # curr = lookup(curr->next)
 8497       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
 8498       e9/jump loop/disp32
 8499     }
 8500 $emit-subx:end:
 8501     # . restore registers
 8502     58/pop-to-eax
 8503     # . epilogue
 8504     89/<- %esp 5/r32/ebp
 8505     5d/pop-to-ebp
 8506     c3/return
 8507 
 8508 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8509     # . prologue
 8510     55/push-ebp
 8511     89/<- %ebp 4/r32/esp
 8512     # some preprocessing
 8513     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
 8514     # . save registers
 8515     50/push-eax
 8516     51/push-ecx
 8517     52/push-edx
 8518     57/push-edi
 8519     # initialize some global state
 8520     c7 0/subop/copy *Curr-block-depth 1/imm32
 8521     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
 8522     # ecx = f
 8523     8b/-> *(ebp+0xc) 1/r32/ecx
 8524     # var vars/edx: (stack (addr var) 256)
 8525     81 5/subop/subtract %esp 0xc00/imm32
 8526     68/push 0xc00/imm32/size
 8527     68/push 0/imm32/top
 8528     89/<- %edx 4/r32/esp
 8529     # var name/eax: (addr array byte) = lookup(f->name)
 8530     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 8531     #
 8532     (write-buffered *(ebp+8) %eax)
 8533     (write-buffered *(ebp+8) ":\n")
 8534     (emit-subx-prologue *(ebp+8))
 8535     # var outputs/edi: (addr list var) = lookup(f->outputs)
 8536     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 8537     89/<- %edi 0/r32/eax
 8538     # var body/eax: (addr block) = lookup(f->body)
 8539     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
 8540     #
 8541     (emit-subx-block *(ebp+8) %eax %edx %edi *(ebp+0x10) *(ebp+0x14))
 8542     (emit-subx-epilogue *(ebp+8))
 8543     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
 8544     # been cleaned up
 8545 $emit-subx-function:end:
 8546     # . reclaim locals
 8547     81 0/subop/add %esp 0xc08/imm32
 8548     # . restore registers
 8549     5f/pop-to-edi
 8550     5a/pop-to-edx
 8551     59/pop-to-ecx
 8552     58/pop-to-eax
 8553     # . epilogue
 8554     89/<- %esp 5/r32/ebp
 8555     5d/pop-to-ebp
 8556     c3/return
 8557 
 8558 populate-mu-type-offsets-in-inouts:  # f: (addr function)
 8559     # . prologue
 8560     55/push-ebp
 8561     89/<- %ebp 4/r32/esp
 8562     # . save registers
 8563     50/push-eax
 8564     51/push-ecx
 8565     52/push-edx
 8566     53/push-ebx
 8567     57/push-edi
 8568     # var next-offset/edx: int = 8
 8569     ba/copy-to-edx 8/imm32
 8570     # var curr/ecx: (addr list var) = lookup(f->inouts)
 8571     8b/-> *(ebp+8) 1/r32/ecx
 8572     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 8573     89/<- %ecx 0/r32/eax
 8574     {
 8575 $populate-mu-type-offsets-in-inouts:loop:
 8576       81 7/subop/compare %ecx 0/imm32
 8577       74/jump-if-= break/disp8
 8578       # var v/ebx: (addr var) = lookup(curr->value)
 8579       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 8580       89/<- %ebx 0/r32/eax
 8581 #?       (lookup *ebx *(ebx+4))
 8582 #?       (write-buffered Stderr "setting offset of fn inout ")
 8583 #?       (write-buffered Stderr %eax)
 8584 #?       (write-buffered Stderr "@")
 8585 #?       (print-int32-buffered Stderr %ebx)
 8586 #?       (write-buffered Stderr " to ")
 8587 #?       (print-int32-buffered Stderr %edx)
 8588 #?       (write-buffered Stderr Newline)
 8589 #?       (flush Stderr)
 8590       # v->offset = next-offset
 8591       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
 8592       # next-offset += size-of(v)
 8593       (size-of %ebx)  # => eax
 8594       01/add-to %edx 0/r32/eax
 8595       # curr = lookup(curr->next)
 8596       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 8597       89/<- %ecx 0/r32/eax
 8598       #
 8599       eb/jump loop/disp8
 8600     }
 8601 $populate-mu-type-offsets-in-inouts:end:
 8602     # . restore registers
 8603     5f/pop-to-edi
 8604     5b/pop-to-ebx
 8605     5a/pop-to-edx
 8606     59/pop-to-ecx
 8607     58/pop-to-eax
 8608     # . epilogue
 8609     89/<- %esp 5/r32/ebp
 8610     5d/pop-to-ebp
 8611     c3/return
 8612 
 8613 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8614     # . prologue
 8615     55/push-ebp
 8616     89/<- %ebp 4/r32/esp
 8617     # . save registers
 8618     50/push-eax
 8619     51/push-ecx
 8620     53/push-ebx
 8621     56/push-esi
 8622     # esi = stmts
 8623     8b/-> *(ebp+0xc) 6/r32/esi
 8624     #
 8625     {
 8626 $emit-subx-stmt-list:loop:
 8627       81 7/subop/compare %esi 0/imm32
 8628       0f 84/jump-if-= break/disp32
 8629       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
 8630       (lookup *esi *(esi+4))  # List-value List-value => eax
 8631       89/<- %ecx 0/r32/eax
 8632       {
 8633 $emit-subx-stmt-list:check-for-block:
 8634         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 8635         75/jump-if-!= break/disp8
 8636 $emit-subx-stmt-list:block:
 8637         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8638       }
 8639       {
 8640 $emit-subx-stmt-list:check-for-stmt:
 8641         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 8642         0f 85/jump-if-!= break/disp32
 8643 $emit-subx-stmt-list:stmt1:
 8644         {
 8645           (is-mu-branch? %ecx)  # => eax
 8646           3d/compare-eax-and 0/imm32/false
 8647           0f 84/jump-if-= break/disp32
 8648 $emit-subx-stmt-list:branch-stmt:
 8649 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
 8676 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
 8692 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
 8730 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
 8749         }
 8750 $emit-subx-stmt-list:1-to-1:
 8751         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
 8752         e9/jump $emit-subx-stmt-list:continue/disp32
 8753       }
 8754       {
 8755 $emit-subx-stmt-list:check-for-var-def:
 8756         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
 8757         75/jump-if-!= break/disp8
 8758 $emit-subx-stmt-list:var-def:
 8759         (emit-subx-var-def *(ebp+8) %ecx)
 8760         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
 8761         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
 8762         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
 8763         #
 8764         eb/jump $emit-subx-stmt-list:continue/disp8
 8765       }
 8766       {
 8767 $emit-subx-stmt-list:check-for-reg-var-def:
 8768         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
 8769         0f 85/jump-if-!= break/disp32
 8770 $emit-subx-stmt-list:reg-var-def:
 8771         # TODO: ensure that there's exactly one output
 8772         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8773         # emit the instruction as usual
 8774         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
 8775         #
 8776         eb/jump $emit-subx-stmt-list:continue/disp8
 8777       }
 8778 $emit-subx-stmt-list:continue:
 8779       # TODO: raise an error on unrecognized Stmt-tag
 8780       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
 8781       89/<- %esi 0/r32/eax
 8782       e9/jump loop/disp32
 8783     }
 8784 $emit-subx-stmt-list:emit-cleanup:
 8785     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
 8786 $emit-subx-stmt-list:clean-up:
 8787     (clean-up-blocks *(ebp+0x10) *Curr-block-depth)
 8788 $emit-subx-stmt-list:end:
 8789     # . restore registers
 8790     5e/pop-to-esi
 8791     5b/pop-to-ebx
 8792     59/pop-to-ecx
 8793     58/pop-to-eax
 8794     # . epilogue
 8795     89/<- %esp 5/r32/ebp
 8796     5d/pop-to-ebp
 8797     c3/return
 8798 
 8799 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
 8800 push-output-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var)), later-stmts: (addr list stmt), fn-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
 8801     # . prologue
 8802     55/push-ebp
 8803     89/<- %ebp 4/r32/esp
 8804     # . save registers
 8805     50/push-eax
 8806     51/push-ecx
 8807     52/push-edx
 8808     # ecx = stmt
 8809     8b/-> *(ebp+0xc) 1/r32/ecx
 8810     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
 8811     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8812     # TODO: assert !sv->is-deref?
 8813     # var v/ecx: (addr var) = lookup(sv->value)
 8814     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8815     89/<- %ecx 0/r32/eax
 8816     # v->block-depth = *Curr-block-depth
 8817     8b/-> *Curr-block-depth 0/r32/eax
 8818     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 8819 #?     (write-buffered Stderr "var ")
 8820 #?     (lookup *ecx *(ecx+4))
 8821 #?     (write-buffered Stderr %eax)
 8822 #?     (write-buffered Stderr " at depth ")
 8823 #?     (print-int32-buffered Stderr *(ecx+0x10))
 8824 #?     (write-buffered Stderr Newline)
 8825 #?     (flush Stderr)
 8826     # ensure that v is in a register
 8827     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 8828     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
 8829     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn-outputs)
 8830     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
 8831     89/<- %edx 0/r32/eax
 8832     3d/compare-eax-and 0/imm32/false
 8833     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
 8834     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
 8835     89/<- %edx 0/r32/eax
 8836     # check emit-spill?
 8837     3d/compare-eax-and 0/imm32/false
 8838     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
 8839     # TODO: assert(size-of(output) == 4)
 8840     # *Curr-local-stack-offset -= 4
 8841     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
 8842     # emit spill
 8843     (emit-indent *(ebp+8) *Curr-block-depth)
 8844     (write-buffered *(ebp+8) "ff 6/subop/push %")
 8845     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8846     (write-buffered *(ebp+8) %eax)
 8847     (write-buffered *(ebp+8) Newline)
 8848 $push-output-and-maybe-emit-spill:push:
 8849     8b/-> *(ebp+0xc) 1/r32/ecx
 8850     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8851     # push(vars, {sv->value, emit-spill?})
 8852     (push *(ebp+0x10) *eax)  # Stmt-var-value
 8853     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
 8854     (push *(ebp+0x10) %edx)
 8855 $push-output-and-maybe-emit-spill:end:
 8856     # . restore registers
 8857     5a/pop-to-edx
 8858     59/pop-to-ecx
 8859     58/pop-to-eax
 8860     # . epilogue
 8861     89/<- %esp 5/r32/ebp
 8862     5d/pop-to-ebp
 8863     c3/return
 8864 
 8865 $push-output-and-maybe-emit-spill:abort:
 8866     # error("var '" var->name "' initialized from an instruction must live in a register\n")
 8867     (write-buffered *(ebp+0x1c) "var '")
 8868     (write-buffered *(ebp+0x1c) *eax)  # Var-name
 8869     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
 8870     (flush *(ebp+0x1c))
 8871     (stop *(ebp+0x20) 1)
 8872     # never gets here
 8873 
 8874 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
 8875     # . prologue
 8876     55/push-ebp
 8877     89/<- %ebp 4/r32/esp
 8878     # . save registers
 8879     50/push-eax
 8880     51/push-ecx
 8881     # ecx = stmt
 8882     8b/-> *(ebp+0xc) 1/r32/ecx
 8883     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
 8884     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8885     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8886     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8887     # clean up until target block
 8888     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
 8889     # emit jump to target block
 8890     (emit-indent *(ebp+8) *Curr-block-depth)
 8891     (write-buffered *(ebp+8) "e9/jump ")
 8892     (write-buffered *(ebp+8) %eax)
 8893     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8894     (string-starts-with? %eax "break")
 8895     3d/compare-eax-and 0/imm32/false
 8896     {
 8897       74/jump-if-= break/disp8
 8898       (write-buffered *(ebp+8) ":break/disp32\n")
 8899     }
 8900     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
 8901     {
 8902       75/jump-if-!= break/disp8
 8903       (write-buffered *(ebp+8) ":loop/disp32\n")
 8904     }
 8905 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
 8906     # . restore registers
 8907     59/pop-to-ecx
 8908     58/pop-to-eax
 8909     # . epilogue
 8910     89/<- %esp 5/r32/ebp
 8911     5d/pop-to-ebp
 8912     c3/return
 8913 
 8914 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
 8915     # . prologue
 8916     55/push-ebp
 8917     89/<- %ebp 4/r32/esp
 8918     # . save registers
 8919     51/push-ecx
 8920     # ecx = lookup(stmt->operation)
 8921     8b/-> *(ebp+8) 1/r32/ecx
 8922     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 8923     89/<- %ecx 0/r32/eax
 8924     # if (stmt->operation starts with "loop") return true
 8925     (string-starts-with? %ecx "loop")  # => eax
 8926     3d/compare-eax-and 0/imm32/false
 8927     75/jump-if-not-equal $is-mu-branch?:end/disp8
 8928     # otherwise return (stmt->operation starts with "break")
 8929     (string-starts-with? %ecx "break")  # => eax
 8930 $is-mu-branch?:end:
 8931     # . restore registers
 8932     59/pop-to-ecx
 8933     # . epilogue
 8934     89/<- %esp 5/r32/ebp
 8935     5d/pop-to-ebp
 8936     c3/return
 8937 
 8938 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
 8939     # . prologue
 8940     55/push-ebp
 8941     89/<- %ebp 4/r32/esp
 8942     # . save registers
 8943     50/push-eax
 8944     # eax = stmt
 8945     8b/-> *(ebp+0xc) 0/r32/eax
 8946     #
 8947     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
 8948     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
 8949     (emit-indent *(ebp+8) *Curr-block-depth)
 8950     (lookup *eax *(eax+4))  # => eax
 8951     (write-buffered *(ebp+8) %eax)
 8952     (write-buffered *(ebp+8) " break/disp32\n")
 8953 $emit-reverse-break:end:
 8954     # . restore registers
 8955     58/pop-to-eax
 8956     # . epilogue
 8957     89/<- %esp 5/r32/ebp
 8958     5d/pop-to-ebp
 8959     c3/return
 8960 
 8961 == data
 8962 
 8963 # Table from Mu branch instructions to the reverse SubX opcodes for them.
 8964 Reverse-branch:  # (table (handle array byte) (handle array byte))
 8965   # a table is a stream
 8966   0x140/imm32/write
 8967   0/imm32/read
 8968   0x140/imm32/size
 8969   # data
 8970   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8971   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
 8972   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8973   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
 8974   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8975   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
 8976   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8977   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
 8978   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8979   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8980   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8981   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
 8982   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8983   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
 8984   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8985   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
 8986   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8987   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
 8988   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8989   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
 8990 
 8991 == code
 8992 
 8993 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
 8994     # . prologue
 8995     55/push-ebp
 8996     89/<- %ebp 4/r32/esp
 8997     # . save registers
 8998     50/push-eax
 8999     51/push-ecx
 9000     52/push-edx
 9001     53/push-ebx
 9002     56/push-esi
 9003     # ecx = vars
 9004     8b/-> *(ebp+0xc) 1/r32/ecx
 9005     # var eax: int = vars->top
 9006     8b/-> *ecx 0/r32/eax
 9007     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9008     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
 9009     # var min/ecx: (addr handle var) = vars->data
 9010     8d/copy-address *(ecx+8) 1/r32/ecx
 9011     # edx = depth
 9012     8b/-> *(ebp+0x10) 2/r32/edx
 9013     {
 9014 $emit-unconditional-jump-to-depth:loop:
 9015       # if (curr < min) break
 9016       39/compare %esi 1/r32/ecx
 9017       0f 82/jump-if-addr< break/disp32
 9018       # var v/ebx: (addr var) = lookup(*curr)
 9019       (lookup *esi *(esi+4))  # => eax
 9020       89/<- %ebx 0/r32/eax
 9021       # if (v->block-depth < until-block-depth) break
 9022       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 9023       0f 8c/jump-if-< break/disp32
 9024       {
 9025 $emit-unconditional-jump-to-depth:check:
 9026         # if v->block-depth != until-block-depth, continue
 9027         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 9028         0f 85/jump-if-!= break/disp32
 9029 $emit-unconditional-jump-to-depth:depth-found:
 9030         # if v is not a literal, continue
 9031         (size-of %ebx)  # => eax
 9032         3d/compare-eax-and 0/imm32
 9033         0f 85/jump-if-!= break/disp32
 9034 $emit-unconditional-jump-to-depth:label-found:
 9035         # emit unconditional jump, then return
 9036         (emit-indent *(ebp+8) *Curr-block-depth)
 9037         (write-buffered *(ebp+8) "e9/jump ")
 9038         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 9039         (write-buffered *(ebp+8) %eax)
 9040         (write-buffered *(ebp+8) ":")
 9041         (write-buffered *(ebp+8) *(ebp+0x14))
 9042         (write-buffered *(ebp+8) "/disp32\n")
 9043         eb/jump $emit-unconditional-jump-to-depth:end/disp8
 9044       }
 9045       # curr -= 12
 9046       81 5/subop/subtract %esi 0xc/imm32
 9047       e9/jump loop/disp32
 9048     }
 9049     # TODO: error if no label at 'depth' was found
 9050 $emit-unconditional-jump-to-depth:end:
 9051     # . restore registers
 9052     5e/pop-to-esi
 9053     5b/pop-to-ebx
 9054     5a/pop-to-edx
 9055     59/pop-to-ecx
 9056     58/pop-to-eax
 9057     # . epilogue
 9058     89/<- %esp 5/r32/ebp
 9059     5d/pop-to-ebp
 9060     c3/return
 9061 
 9062 # emit clean-up code for 'vars' until some block depth
 9063 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 9064 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
 9065     # . prologue
 9066     55/push-ebp
 9067     89/<- %ebp 4/r32/esp
 9068     # . save registers
 9069     50/push-eax
 9070     51/push-ecx
 9071     52/push-edx
 9072     53/push-ebx
 9073     56/push-esi
 9074 #?     (write-buffered Stderr "--- cleanup\n")
 9075 #?     (flush Stderr)
 9076     # ecx = vars
 9077     8b/-> *(ebp+0xc) 1/r32/ecx
 9078     # var esi: int = vars->top
 9079     8b/-> *ecx 6/r32/esi
 9080     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9081     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
 9082     # var min/ecx: (addr handle var) = vars->data
 9083     81 0/subop/add %ecx 8/imm32
 9084     # edx = until-block-depth
 9085     8b/-> *(ebp+0x10) 2/r32/edx
 9086     {
 9087 $emit-cleanup-code-until-depth:loop:
 9088       # if (curr < min) break
 9089       39/compare %esi 1/r32/ecx
 9090       0f 82/jump-if-addr< break/disp32
 9091       # var v/ebx: (addr var) = lookup(*curr)
 9092       (lookup *esi *(esi+4))  # => eax
 9093       89/<- %ebx 0/r32/eax
 9094 #?       (lookup *ebx *(ebx+4))  # Var-name
 9095 #?       (write-buffered Stderr "var ")
 9096 #?       (write-buffered Stderr %eax)
 9097 #?       (write-buffered Stderr Newline)
 9098 #?       (flush Stderr)
 9099       # if (v->block-depth < until-block-depth) break
 9100       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
 9101       0f 8c/jump-if-< break/disp32
 9102       # if v is in a register
 9103       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 9104       {
 9105         0f 84/jump-if-= break/disp32
 9106         {
 9107 $emit-cleanup-code-until-depth:check-for-previous-spill:
 9108           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
 9109           3d/compare-eax-and 0/imm32/false
 9110           74/jump-if-= break/disp8
 9111 $emit-cleanup-code-until-depth:reclaim-var-in-register:
 9112           (emit-indent *(ebp+8) *Curr-block-depth)
 9113           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 9114           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9115           (write-buffered *(ebp+8) %eax)
 9116           (write-buffered *(ebp+8) Newline)
 9117         }
 9118         eb/jump $emit-cleanup-code-until-depth:continue/disp8
 9119       }
 9120       # otherwise v is on the stack
 9121       {
 9122         75/jump-if-!= break/disp8
 9123 $emit-cleanup-code-until-depth:var-on-stack:
 9124         (size-of %ebx)  # => eax
 9125         # don't emit code for labels
 9126         3d/compare-eax-and 0/imm32
 9127         74/jump-if-= break/disp8
 9128 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
 9129         (emit-indent *(ebp+8) *Curr-block-depth)
 9130         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 9131         (print-int32-buffered *(ebp+8) %eax)
 9132         (write-buffered *(ebp+8) "/imm32\n")
 9133       }
 9134 $emit-cleanup-code-until-depth:continue:
 9135       # curr -= 12
 9136       81 5/subop/subtract %esi 0xc/imm32
 9137       e9/jump loop/disp32
 9138     }
 9139 $emit-cleanup-code-until-depth:end:
 9140     # . restore registers
 9141     5e/pop-to-esi
 9142     5b/pop-to-ebx
 9143     5a/pop-to-edx
 9144     59/pop-to-ecx
 9145     58/pop-to-eax
 9146     # . epilogue
 9147     89/<- %esp 5/r32/ebp
 9148     5d/pop-to-ebp
 9149     c3/return
 9150 
 9151 # emit clean-up code for 'vars' until a given label is encountered
 9152 # doesn't actually modify 'vars' so we need traverse manually inside the stack
 9153 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
 9154     # . prologue
 9155     55/push-ebp
 9156     89/<- %ebp 4/r32/esp
 9157     # . save registers
 9158     50/push-eax
 9159     51/push-ecx
 9160     52/push-edx
 9161     53/push-ebx
 9162     # ecx = vars
 9163     8b/-> *(ebp+0xc) 1/r32/ecx
 9164     # var eax: int = vars->top
 9165     8b/-> *ecx 0/r32/eax
 9166     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
 9167     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
 9168     # var min/ecx: (addr handle var) = vars->data
 9169     81 0/subop/add %ecx 8/imm32
 9170     {
 9171 $emit-cleanup-code-until-target:loop:
 9172       # if (curr < min) break
 9173       39/compare %edx 1/r32/ecx
 9174       0f 82/jump-if-addr< break/disp32
 9175       # var v/ebx: (handle var) = lookup(*curr)
 9176       (lookup *edx *(edx+4))  # => eax
 9177       89/<- %ebx 0/r32/eax
 9178       # if (v->name == until-block-label) break
 9179       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 9180       (string-equal? %eax *(ebp+0x10))  # => eax
 9181       3d/compare-eax-and 0/imm32/false
 9182       0f 85/jump-if-!= break/disp32
 9183       # if v is in a register
 9184       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
 9185       {
 9186         0f 84/jump-if-= break/disp32
 9187         {
 9188 $emit-cleanup-code-until-target:check-for-previous-spill:
 9189           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
 9190           3d/compare-eax-and 0/imm32/false
 9191           74/jump-if-= break/disp8
 9192 $emit-cleanup-code-until-target:reclaim-var-in-register:
 9193           (emit-indent *(ebp+8) *Curr-block-depth)
 9194           (write-buffered *(ebp+8) "8f 0/subop/pop %")
 9195           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9196           (write-buffered *(ebp+8) %eax)
 9197           (write-buffered *(ebp+8) Newline)
 9198         }
 9199         eb/jump $emit-cleanup-code-until-target:continue/disp8
 9200       }
 9201       # otherwise v is on the stack
 9202       {
 9203         75/jump-if-!= break/disp8
 9204 $emit-cleanup-code-until-target:reclaim-var-on-stack:
 9205         (size-of %ebx)  # => eax
 9206         # don't emit code for labels
 9207         3d/compare-eax-and 0/imm32
 9208         74/jump-if-= break/disp8
 9209         #
 9210         (emit-indent *(ebp+8) *Curr-block-depth)
 9211         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
 9212         (print-int32-buffered *(ebp+8) %eax)
 9213         (write-buffered *(ebp+8) "/imm32\n")
 9214       }
 9215 $emit-cleanup-code-until-target:continue:
 9216       # curr -= 12
 9217       81 5/subop/subtract %edx 0xc/imm32
 9218       e9/jump loop/disp32
 9219     }
 9220 $emit-cleanup-code-until-target:end:
 9221     # . restore registers
 9222     5b/pop-to-ebx
 9223     5a/pop-to-edx
 9224     59/pop-to-ecx
 9225     58/pop-to-eax
 9226     # . epilogue
 9227     89/<- %esp 5/r32/ebp
 9228     5d/pop-to-ebp
 9229     c3/return
 9230 
 9231 # Return true if there isn't a variable in 'vars' with the same block-depth
 9232 # and register as 'v'.
 9233 # 'v' is guaranteed not to be within 'vars'.
 9234 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9235     # . prologue
 9236     55/push-ebp
 9237     89/<- %ebp 4/r32/esp
 9238     # . save registers
 9239     51/push-ecx
 9240     52/push-edx
 9241     53/push-ebx
 9242     56/push-esi
 9243     57/push-edi
 9244     # ecx = vars
 9245     8b/-> *(ebp+0xc) 1/r32/ecx
 9246     # var eax: int = vars->top
 9247     8b/-> *ecx 0/r32/eax
 9248     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
 9249     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
 9250     # var min/ecx: (addr handle var) = vars->data
 9251     8d/copy-address *(ecx+8) 1/r32/ecx
 9252     # var depth/ebx: int = v->block-depth
 9253     8b/-> *(ebp+8) 3/r32/ebx
 9254     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
 9255     # var needle/esi: (addr array byte) = v->register
 9256     8b/-> *(ebp+8) 6/r32/esi
 9257     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
 9258     89/<- %esi 0/r32/eax
 9259     {
 9260 $not-yet-spilled-this-block?:loop:
 9261       # if (curr < min) break
 9262       39/compare %edx 1/r32/ecx
 9263       0f 82/jump-if-addr< break/disp32
 9264       # var cand/edi: (addr var) = lookup(*curr)
 9265       (lookup *edx *(edx+4))  # => eax
 9266       89/<- %edi 0/r32/eax
 9267       # if (cand->block-depth < depth) break
 9268       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
 9269       0f 8c/jump-if-< break/disp32
 9270       # var cand-reg/edi: (array array byte) = cand->reg
 9271       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
 9272       89/<- %edi 0/r32/eax
 9273       # if (cand-reg == null) continue
 9274       {
 9275 $not-yet-spilled-this-block?:check-reg:
 9276         81 7/subop/compare %edi 0/imm32
 9277         0f 84/jump-if-= break/disp32
 9278         # if (cand-reg == needle) return true
 9279         (string-equal? %esi %edi)  # => eax
 9280         3d/compare-eax-and 0/imm32/false
 9281         74/jump-if-= break/disp8
 9282 $not-yet-spilled-this-block?:return-false:
 9283         b8/copy-to-eax 0/imm32/false
 9284         eb/jump $not-yet-spilled-this-block?:end/disp8
 9285       }
 9286 $not-yet-spilled-this-block?:continue:
 9287       # curr -= 12
 9288       81 5/subop/subtract %edx 0xc/imm32
 9289       e9/jump loop/disp32
 9290     }
 9291 $not-yet-spilled-this-block?:return-true:
 9292     # return true
 9293     b8/copy-to-eax 1/imm32/true
 9294 $not-yet-spilled-this-block?:end:
 9295     # . restore registers
 9296     5f/pop-to-edi
 9297     5e/pop-to-esi
 9298     5b/pop-to-ebx
 9299     5a/pop-to-edx
 9300     59/pop-to-ecx
 9301     # . epilogue
 9302     89/<- %esp 5/r32/ebp
 9303     5d/pop-to-ebp
 9304     c3/return
 9305 
 9306 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
 9307 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn-outputs: (addr list var) -> result/eax: boolean
 9308     # . prologue
 9309     55/push-ebp
 9310     89/<- %ebp 4/r32/esp
 9311     # eax = v
 9312     8b/-> *(ebp+8) 0/r32/eax
 9313     # var reg/eax: (addr array byte) = lookup(v->register)
 9314     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9315     # var target/eax: (addr var) = find-register(fn-outputs, reg)
 9316     (find-register *(ebp+0x10) %eax)  # => eax
 9317     # if (target == 0) return true
 9318     {
 9319       3d/compare-eax-and 0/imm32
 9320       75/jump-if-!= break/disp8
 9321       b8/copy-to-eax 1/imm32/true
 9322       eb/jump $will-not-write-some-register?:end/disp8
 9323     }
 9324     # return !assigns-in-stmts?(stmts, target)
 9325     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
 9326     3d/compare-eax-and 0/imm32/false
 9327     # assume: true = 1, so no need to mask with 0x000000ff
 9328     0f 94/set-if-= %al
 9329 $will-not-write-some-register?:end:
 9330     # . epilogue
 9331     89/<- %esp 5/r32/ebp
 9332     5d/pop-to-ebp
 9333     c3/return
 9334 
 9335 # return output var with matching register
 9336 # always returns false if 'reg' is null
 9337 find-register:  # fn-outputs: (addr list var), reg: (addr array byte) -> result/eax: (addr var)
 9338     # . prologue
 9339     55/push-ebp
 9340     89/<- %ebp 4/r32/esp
 9341     # . save registers
 9342     51/push-ecx
 9343     # var curr/ecx: (addr list var) = fn-outputs
 9344     8b/-> *(ebp+8) 1/r32/ecx
 9345     {
 9346 $find-register:loop:
 9347       # if (curr == 0) break
 9348       81 7/subop/compare %ecx 0/imm32
 9349       74/jump-if-= break/disp8
 9350       # eax = curr->value->register
 9351       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9352       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9353       # if (eax == reg) return curr->value
 9354 $find-register:compare:
 9355       (string-equal? *(ebp+0xc) %eax)  # => eax
 9356       {
 9357         3d/compare-eax-and 0/imm32/false
 9358         74/jump-if-= break/disp8
 9359 $find-register:found:
 9360         (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9361         eb/jump $find-register:end/disp8
 9362       }
 9363       # curr = lookup(curr->next)
 9364       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9365       89/<- %ecx 0/r32/eax
 9366       #
 9367       eb/jump loop/disp8
 9368     }
 9369 $find-register:end:
 9370     # . restore registers
 9371     59/pop-to-ecx
 9372     # . epilogue
 9373     89/<- %esp 5/r32/ebp
 9374     5d/pop-to-ebp
 9375     c3/return
 9376 
 9377 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
 9378     # . prologue
 9379     55/push-ebp
 9380     89/<- %ebp 4/r32/esp
 9381     # . save registers
 9382     51/push-ecx
 9383     # var curr/ecx: (addr list stmt) = stmts
 9384     8b/-> *(ebp+8) 1/r32/ecx
 9385     {
 9386       # if (curr == 0) break
 9387       81 7/subop/compare %ecx 0/imm32
 9388       74/jump-if-= break/disp8
 9389       # if assigns-in-stmt?(curr->value, v) return true
 9390       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9391       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
 9392       3d/compare-eax-and 0/imm32/false
 9393       75/jump-if-!= break/disp8
 9394       # curr = lookup(curr->next)
 9395       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9396       89/<- %ecx 0/r32/eax
 9397       #
 9398       eb/jump loop/disp8
 9399     }
 9400 $assigns-in-stmts?:end:
 9401     # . restore registers
 9402     59/pop-to-ecx
 9403     # . epilogue
 9404     89/<- %esp 5/r32/ebp
 9405     5d/pop-to-ebp
 9406     c3/return
 9407 
 9408 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
 9409     # . prologue
 9410     55/push-ebp
 9411     89/<- %ebp 4/r32/esp
 9412     # . save registers
 9413     51/push-ecx
 9414     # ecx = stmt
 9415     8b/-> *(ebp+8) 1/r32/ecx
 9416     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
 9417     {
 9418       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
 9419       75/jump-if-!= break/disp8
 9420       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9421       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
 9422       eb/jump $assigns-in-stmt?:end/disp8
 9423     }
 9424     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
 9425     {
 9426       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
 9427       75/jump-if-!= break/disp8
 9428       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
 9429       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
 9430       eb/jump $assigns-in-stmt?:end/disp8
 9431     }
 9432     # otherwise return false
 9433     b8/copy 0/imm32/false
 9434 $assigns-in-stmt?:end:
 9435     # . restore registers
 9436     59/pop-to-ecx
 9437     # . epilogue
 9438     89/<- %esp 5/r32/ebp
 9439     5d/pop-to-ebp
 9440     c3/return
 9441 
 9442 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
 9443     # . prologue
 9444     55/push-ebp
 9445     89/<- %ebp 4/r32/esp
 9446     # . save registers
 9447     51/push-ecx
 9448     # var curr/ecx: (addr stmt-var) = stmt-var
 9449     8b/-> *(ebp+8) 1/r32/ecx
 9450     {
 9451       # if (curr == 0) break
 9452       81 7/subop/compare %ecx 0/imm32
 9453       74/jump-if-= break/disp8
 9454       # eax = lookup(curr->value)
 9455       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
 9456       # if (eax == v  &&  curr->is-deref? == false) return true
 9457       {
 9458         39/compare *(ebp+0xc) 0/r32/eax
 9459         75/jump-if-!= break/disp8
 9460         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
 9461         75/jump-if-!= break/disp8
 9462         b8/copy-to-eax 1/imm32/true
 9463         eb/jump $assigns-in-stmt-vars?:end/disp8
 9464       }
 9465       # curr = lookup(curr->next)
 9466       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
 9467       89/<- %ecx 0/r32/eax
 9468       #
 9469       eb/jump loop/disp8
 9470     }
 9471 $assigns-in-stmt-vars?:end:
 9472     # . restore registers
 9473     59/pop-to-ecx
 9474     # . epilogue
 9475     89/<- %esp 5/r32/ebp
 9476     5d/pop-to-ebp
 9477     c3/return
 9478 
 9479 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
 9480 # v is guaranteed to be within vars
 9481 # 'start' is provided as an optimization, a pointer within vars
 9482 # *start == v
 9483 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
 9484     # . prologue
 9485     55/push-ebp
 9486     89/<- %ebp 4/r32/esp
 9487     # . save registers
 9488     51/push-ecx
 9489     52/push-edx
 9490     53/push-ebx
 9491     56/push-esi
 9492     57/push-edi
 9493     # ecx = v
 9494     8b/-> *(ebp+8) 1/r32/ecx
 9495     # var reg/edx: (addr array byte) = lookup(v->register)
 9496     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 9497     89/<- %edx 0/r32/eax
 9498     # var depth/ebx: int = v->block-depth
 9499     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
 9500     # var min/ecx: (addr handle var) = vars->data
 9501     8b/-> *(ebp+0xc) 1/r32/ecx
 9502     81 0/subop/add %ecx 8/imm32
 9503     # TODO: check that start >= min and start < &vars->data[top]
 9504     # TODO: check that *start == v
 9505     # var curr/esi: (addr handle var) = start
 9506     8b/-> *(ebp+0x10) 6/r32/esi
 9507     # curr -= 8
 9508     81 5/subop/subtract %esi 8/imm32
 9509     {
 9510 $same-register-spilled-before?:loop:
 9511       # if (curr < min) break
 9512       39/compare %esi 1/r32/ecx
 9513       0f 82/jump-if-addr< break/disp32
 9514       # var x/eax: (addr var) = lookup(*curr)
 9515       (lookup *esi *(esi+4))  # => eax
 9516       # if (x->block-depth < depth) break
 9517       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
 9518       0f 8c/jump-if-< break/disp32
 9519       # if (x->register == 0) continue
 9520       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 9521       74/jump-if-= $same-register-spilled-before?:continue/disp8
 9522       # if (x->register == reg) return true
 9523       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9524       (string-equal? %eax %edx)  # => eax
 9525       3d/compare-eax-and 0/imm32/false
 9526       b8/copy-to-eax 1/imm32/true
 9527       75/jump-if-!= $same-register-spilled-before?:end/disp8
 9528 $same-register-spilled-before?:continue:
 9529       # curr -= 8
 9530       81 5/subop/subtract %esi 8/imm32
 9531       e9/jump loop/disp32
 9532     }
 9533 $same-register-spilled-before?:false:
 9534     b8/copy-to-eax 0/imm32/false
 9535 $same-register-spilled-before?:end:
 9536     # . restore registers
 9537     5f/pop-to-edi
 9538     5e/pop-to-esi
 9539     5b/pop-to-ebx
 9540     5a/pop-to-edx
 9541     59/pop-to-ecx
 9542     # . epilogue
 9543     89/<- %esp 5/r32/ebp
 9544     5d/pop-to-ebp
 9545     c3/return
 9546 
 9547 # clean up global state for 'vars' until some block depth
 9548 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int
 9549     # . prologue
 9550     55/push-ebp
 9551     89/<- %ebp 4/r32/esp
 9552     # . save registers
 9553     50/push-eax
 9554     51/push-ecx
 9555     56/push-esi
 9556     # esi = vars
 9557     8b/-> *(ebp+8) 6/r32/esi
 9558     # ecx = until-block-depth
 9559     8b/-> *(ebp+0xc) 1/r32/ecx
 9560     {
 9561 $clean-up-blocks:reclaim-loop:
 9562       # if (vars->top <= 0) break
 9563       8b/-> *esi 0/r32/eax  # Stack-top
 9564       3d/compare-eax-and 0/imm32
 9565       0f 8e/jump-if-<= break/disp32
 9566       # var v/eax: (addr var) = lookup(vars[vars->top-12])
 9567 #?       (print-int32-buffered Stderr %eax)
 9568 #?       (write-buffered Stderr ": ")
 9569 #?       (print-int32-buffered Stderr *(esi+eax-4))
 9570 #?       (write-buffered Stderr " ")
 9571 #?       (print-int32-buffered Stderr *(esi+eax))
 9572 #?       (write-buffered Stderr " ")
 9573 #?       (print-int32-buffered Stderr *(esi+eax+4))
 9574 #?       (write-buffered Stderr Newline)
 9575 #?       (flush Stderr)
 9576       (lookup *(esi+eax-4) *(esi+eax))  # vars + 8 + vars->top - 12 => eax
 9577       # if (v->block-depth < until-block-depth) break
 9578       39/compare *(eax+0x10) 1/r32/ecx  # Var-block-depth
 9579       7c/jump-if-< break/disp8
 9580       # if v is on the stack, update Curr-local-stack-offset
 9581       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 9582       {
 9583         75/jump-if-!= break/disp8
 9584 $clean-up-blocks:reclaim-var-on-stack:
 9585         (size-of %eax)  # => eax
 9586         01/add-to *Curr-local-stack-offset 0/r32/eax
 9587       }
 9588       (pop %esi)  # => eax
 9589       (pop %esi)  # => eax
 9590       (pop %esi)  # => eax
 9591       e9/jump loop/disp32
 9592     }
 9593 $clean-up-blocks:end:
 9594     # . restore registers
 9595     5e/pop-to-esi
 9596     59/pop-to-ecx
 9597     58/pop-to-eax
 9598     # . epilogue
 9599     89/<- %esp 5/r32/ebp
 9600     5d/pop-to-ebp
 9601     c3/return
 9602 
 9603 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
 9604     # . prologue
 9605     55/push-ebp
 9606     89/<- %ebp 4/r32/esp
 9607     # . save registers
 9608     50/push-eax
 9609     51/push-ecx
 9610     52/push-edx
 9611     # eax = stmt
 9612     8b/-> *(ebp+0xc) 0/r32/eax
 9613     # var v/ecx: (addr var)
 9614     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
 9615     89/<- %ecx 0/r32/eax
 9616     # v->block-depth = *Curr-block-depth
 9617     8b/-> *Curr-block-depth 0/r32/eax
 9618     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9619     # var n/edx: int = size-of(stmt->var)
 9620     (size-of %ecx)  # => eax
 9621     89/<- %edx 0/r32/eax
 9622     # *Curr-local-stack-offset -= n
 9623     29/subtract-from *Curr-local-stack-offset 2/r32/edx
 9624     # v->offset = *Curr-local-stack-offset
 9625     8b/-> *Curr-local-stack-offset 0/r32/eax
 9626     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
 9627     # if v is an array, do something special
 9628     {
 9629       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9630       (is-mu-array? %eax)  # => eax
 9631       3d/compare-eax-and 0/imm32/false
 9632       0f 84/jump-if-= break/disp32
 9633       # var array-size-without-size/edx: int = n-4
 9634       81 5/subop/subtract %edx 4/imm32
 9635       (emit-indent *(ebp+8) *Curr-block-depth)
 9636       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
 9637       (print-int32-buffered *(ebp+8) %edx)
 9638       (write-buffered *(ebp+8) ")\n")
 9639       (emit-indent *(ebp+8) *Curr-block-depth)
 9640       (write-buffered *(ebp+8) "68/push ")
 9641       (print-int32-buffered *(ebp+8) %edx)
 9642       (write-buffered *(ebp+8) "/imm32\n")
 9643       eb/jump $emit-subx-var-def:end/disp8
 9644     }
 9645     # while n > 0
 9646     {
 9647       81 7/subop/compare %edx 0/imm32
 9648       7e/jump-if-<= break/disp8
 9649       (emit-indent *(ebp+8) *Curr-block-depth)
 9650       (write-buffered *(ebp+8) "68/push 0/imm32\n")
 9651       # n -= 4
 9652       81 5/subop/subtract %edx 4/imm32
 9653       #
 9654       eb/jump loop/disp8
 9655     }
 9656 $emit-subx-var-def:end:
 9657     # . restore registers
 9658     5a/pop-to-edx
 9659     59/pop-to-ecx
 9660     58/pop-to-eax
 9661     # . epilogue
 9662     89/<- %esp 5/r32/ebp
 9663     5d/pop-to-ebp
 9664     c3/return
 9665 
 9666 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
 9667     # . prologue
 9668     55/push-ebp
 9669     89/<- %ebp 4/r32/esp
 9670     # . save registers
 9671     50/push-eax
 9672     51/push-ecx
 9673     # - some special-case primitives that don't actually use the 'primitives' data structure
 9674     # var op/ecx: (addr array byte) = lookup(stmt->operation)
 9675     8b/-> *(ebp+0xc) 1/r32/ecx
 9676     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
 9677     89/<- %ecx 0/r32/eax
 9678     # array size
 9679     {
 9680       # if (!string-equal?(stmt->operation, "length")) break
 9681       (string-equal? %ecx "length")  # => eax
 9682       3d/compare-eax-and 0/imm32
 9683       0f 84/jump-if-= break/disp32
 9684       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc))
 9685       e9/jump $emit-subx-stmt:end/disp32
 9686     }
 9687     # index into array
 9688     {
 9689       # if (!string-equal?(stmt->operation, "index")) break
 9690       (string-equal? %ecx "index")  # => eax
 9691       3d/compare-eax-and 0/imm32
 9692       0f 84/jump-if-= break/disp32
 9693       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
 9694       e9/jump $emit-subx-stmt:end/disp32
 9695     }
 9696     # compute-offset for index into array
 9697     {
 9698       # if (!string-equal?(stmt->operation, "compute-offset")) break
 9699       (string-equal? %ecx "compute-offset")  # => eax
 9700       3d/compare-eax-and 0/imm32
 9701       0f 84/jump-if-= break/disp32
 9702       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc))
 9703       e9/jump $emit-subx-stmt:end/disp32
 9704     }
 9705     # get field from record
 9706     {
 9707       # if (!string-equal?(stmt->operation, "get")) break
 9708       (string-equal? %ecx "get")  # => eax
 9709       3d/compare-eax-and 0/imm32
 9710       0f 84/jump-if-= break/disp32
 9711       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
 9712       e9/jump $emit-subx-stmt:end/disp32
 9713     }
 9714     # - if stmt matches a primitive, emit it
 9715     {
 9716 $emit-subx-stmt:check-for-primitive:
 9717       # var curr/eax: (addr primitive)
 9718       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
 9719       3d/compare-eax-and 0/imm32
 9720       74/jump-if-= break/disp8
 9721 $emit-subx-stmt:primitive:
 9722       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
 9723       e9/jump $emit-subx-stmt:end/disp32
 9724     }
 9725     # - otherwise emit a call
 9726     # TODO: type-checking
 9727 $emit-subx-stmt:call:
 9728     (emit-call *(ebp+8) *(ebp+0xc))
 9729 $emit-subx-stmt:end:
 9730     # . restore registers
 9731     59/pop-to-ecx
 9732     58/pop-to-eax
 9733     # . epilogue
 9734     89/<- %esp 5/r32/ebp
 9735     5d/pop-to-ebp
 9736     c3/return
 9737 
 9738 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9739     # . prologue
 9740     55/push-ebp
 9741     89/<- %ebp 4/r32/esp
 9742     # . save registers
 9743     50/push-eax
 9744     51/push-ecx
 9745     52/push-edx
 9746     53/push-ebx
 9747     56/push-esi
 9748     # esi = stmt
 9749     8b/-> *(ebp+0xc) 6/r32/esi
 9750     # var base/ebx: (addr var) = stmt->inouts[0]->value
 9751     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9752     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9753     89/<- %ebx 0/r32/eax
 9754     # var elemsize/ecx: int = element-size(base)
 9755     (array-element-type-id %ebx)  # => eax
 9756     (size-of-type-id %eax)  # => eax
 9757     89/<- %ecx 0/r32/eax
 9758     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
 9759     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 9760     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9761     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9762     89/<- %edx 0/r32/eax
 9763     # if elemsize == 1
 9764     {
 9765       81 7/subop/compare %ecx 1/imm32
 9766       75/jump-if-!= break/disp8
 9767       (emit-save-size-to *(ebp+8) %ebx %edx)
 9768       e9/jump $translate-mu-length-stmt:end/disp32
 9769     }
 9770     # if elemsize is a power of 2 less than 256
 9771     {
 9772       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
 9773       3d/compare-eax-and 0/imm32/false
 9774       74/jump-if-= break/disp8
 9775       81 7/subop/compare %ecx 0xff/imm32
 9776       7f/jump-if-> break/disp8
 9777       (emit-save-size-to *(ebp+8) %ebx %edx)
 9778       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
 9779       e9/jump $translate-mu-length-stmt:end/disp32
 9780     }
 9781     # otherwise, the complex case
 9782     # . emit register spills
 9783     {
 9784       (string-equal? %edx "eax")  # => eax
 9785       3d/compare-eax-and 0/imm32/false
 9786       75/break-if-!= break/disp8
 9787       (emit-indent *(ebp+8) *Curr-block-depth)
 9788       (write-buffered *(ebp+8) "50/push-eax\n")
 9789     }
 9790     {
 9791       (string-equal? %edx "ecx")  # => eax
 9792       3d/compare-eax-and 0/imm32/false
 9793       75/break-if-!= break/disp8
 9794       (emit-indent *(ebp+8) *Curr-block-depth)
 9795       (write-buffered *(ebp+8) "51/push-ecx\n")
 9796     }
 9797     {
 9798       (string-equal? %edx "edx")  # => eax
 9799       3d/compare-eax-and 0/imm32/false
 9800       75/break-if-!= break/disp8
 9801       (emit-indent *(ebp+8) *Curr-block-depth)
 9802       (write-buffered *(ebp+8) "52/push-edx\n")
 9803     }
 9804     # .
 9805     (emit-save-size-to *(ebp+8) %ebx "eax")
 9806     (emit-indent *(ebp+8) *Curr-block-depth)
 9807     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
 9808     (emit-indent *(ebp+8) *Curr-block-depth)
 9809     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
 9810     (print-int32-buffered *(ebp+8) %ecx)
 9811     (write-buffered *(ebp+8) "/imm32\n")
 9812     (emit-indent *(ebp+8) *Curr-block-depth)
 9813     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
 9814     {
 9815       (string-equal? %edx "eax")  # => eax
 9816       3d/compare-eax-and 0/imm32/false
 9817       75/break-if-!= break/disp8
 9818       (emit-indent *(ebp+8) *Curr-block-depth)
 9819       (write-buffered *(ebp+8) "89/<- %")
 9820       (write-buffered *(ebp+8) %edx)
 9821       (write-buffered *(ebp+8) " 0/r32/eax\n")
 9822     }
 9823     # . emit register restores
 9824     {
 9825       (string-equal? %edx "edx")  # => eax
 9826       3d/compare-eax-and 0/imm32/false
 9827       75/break-if-!= break/disp8
 9828       (emit-indent *(ebp+8) *Curr-block-depth)
 9829       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
 9830     }
 9831     {
 9832       (string-equal? %edx "ecx")  # => eax
 9833       3d/compare-eax-and 0/imm32/false
 9834       75/break-if-!= break/disp8
 9835       (emit-indent *(ebp+8) *Curr-block-depth)
 9836       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
 9837     }
 9838     {
 9839       (string-equal? %edx "eax")  # => eax
 9840       3d/compare-eax-and 0/imm32/false
 9841       75/break-if-!= break/disp8
 9842       (emit-indent *(ebp+8) *Curr-block-depth)
 9843       (write-buffered *(ebp+8) "58/pop-to-eax\n")
 9844     }
 9845 $translate-mu-length-stmt:end:
 9846     # . restore registers
 9847     5e/pop-to-esi
 9848     5b/pop-to-ebx
 9849     5a/pop-to-edx
 9850     59/pop-to-ecx
 9851     58/pop-to-eax
 9852     # . epilogue
 9853     89/<- %esp 5/r32/ebp
 9854     5d/pop-to-ebp
 9855     c3/return
 9856 
 9857 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
 9858     # . prologue
 9859     55/push-ebp
 9860     89/<- %ebp 4/r32/esp
 9861     # . save registers
 9862     50/push-eax
 9863     53/push-ebx
 9864     # ebx = base
 9865     8b/-> *(ebp+0xc) 3/r32/ebx
 9866     (emit-indent *(ebp+8) *Curr-block-depth)
 9867     (write-buffered *(ebp+8) "8b/-> *")
 9868     # if base is an (addr array ...) in a register
 9869     {
 9870       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
 9871       74/jump-if-= break/disp8
 9872 $emit-save-size-to:emit-base-from-register:
 9873       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9874       (write-buffered *(ebp+8) %eax)
 9875       eb/jump $emit-save-size-to:emit-output/disp8
 9876     }
 9877     # otherwise if base is an (array ...) on the stack
 9878     {
 9879       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
 9880       74/jump-if-= break/disp8
 9881 $emit-save-size-to:emit-base-from-stack:
 9882       (write-buffered *(ebp+8) "(ebp+")
 9883       (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
 9884       (write-buffered *(ebp+8) ")")
 9885     }
 9886 $emit-save-size-to:emit-output:
 9887     (write-buffered *(ebp+8) " ")
 9888     (get Registers *(ebp+0x10) 0xc "Registers")  # => eax
 9889     (print-int32-buffered *(ebp+8) *eax)
 9890     (write-buffered *(ebp+8) "/r32\n")
 9891 $emit-save-size-to:end:
 9892     # . restore registers
 9893     5b/pop-to-ebx
 9894     58/pop-to-eax
 9895     # . epilogue
 9896     89/<- %esp 5/r32/ebp
 9897     5d/pop-to-ebp
 9898     c3/return
 9899 
 9900 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
 9901     # . prologue
 9902     55/push-ebp
 9903     89/<- %ebp 4/r32/esp
 9904     # . save registers
 9905     50/push-eax
 9906     #
 9907     (emit-indent *(ebp+8) *Curr-block-depth)
 9908     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
 9909     (write-buffered *(ebp+8) *(ebp+0xc))
 9910     (write-buffered *(ebp+8) Space)
 9911     (num-shift-rights *(ebp+0x10))  # => eax
 9912     (print-int32-buffered *(ebp+8) %eax)
 9913     (write-buffered *(ebp+8) "/imm8\n")
 9914 $emit-divide-by-shift-right:end:
 9915     # . restore registers
 9916     58/pop-to-eax
 9917     # . epilogue
 9918     89/<- %esp 5/r32/ebp
 9919     5d/pop-to-ebp
 9920     c3/return
 9921 
 9922 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9923     # . prologue
 9924     55/push-ebp
 9925     89/<- %ebp 4/r32/esp
 9926     # . save registers
 9927     51/push-ecx
 9928     # ecx = stmt
 9929     8b/-> *(ebp+0xc) 1/r32/ecx
 9930     # var base/ecx: (addr var) = stmt->inouts[0]
 9931     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9932     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9933     89/<- %ecx 0/r32/eax
 9934     # if (var->register) do one thing
 9935     {
 9936       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
 9937       74/jump-if-= break/disp8
 9938       # TODO: ensure there's no dereference
 9939       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9940       eb/jump $translate-mu-index-stmt:end/disp8
 9941     }
 9942     # if (var->offset) do a different thing
 9943     {
 9944       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
 9945       74/jump-if-= break/disp8
 9946       # TODO: ensure there's no dereference
 9947       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
 9948       eb/jump $translate-mu-index-stmt:end/disp8
 9949     }
 9950 $translate-mu-index-stmt:end:
 9951     # . restore registers
 9952     59/pop-to-ecx
 9953     # . epilogue
 9954     89/<- %esp 5/r32/ebp
 9955     5d/pop-to-ebp
 9956     c3/return
 9957 
 9958 $translate-mu-index-stmt-with-array:error1:
 9959     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
 9960     (flush *(ebp+0x10))
 9961     (stop *(ebp+0x14) 1)
 9962     # never gets here
 9963 
 9964 $translate-mu-index-stmt-with-array:error2:
 9965     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
 9966     (flush *(ebp+0x10))
 9967     (stop *(ebp+0x14) 1)
 9968     # never gets here
 9969 
 9970 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
 9971     # . prologue
 9972     55/push-ebp
 9973     89/<- %ebp 4/r32/esp
 9974     # . save registers
 9975     50/push-eax
 9976     51/push-ecx
 9977     52/push-edx
 9978     53/push-ebx
 9979     #
 9980     (emit-indent *(ebp+8) *Curr-block-depth)
 9981     (write-buffered *(ebp+8) "8d/copy-address *(")
 9982     # TODO: ensure inouts[0] is in a register and not dereferenced
 9983 $translate-mu-index-stmt-with-array-in-register:emit-base:
 9984     # ecx = stmt
 9985     8b/-> *(ebp+0xc) 1/r32/ecx
 9986     # var base/ebx: (addr var) = inouts[0]
 9987     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9988     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9989     89/<- %ebx 0/r32/eax
 9990     # print base->register " + "
 9991     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 9992     (write-buffered *(ebp+8) %eax)
 9993     (write-buffered *(ebp+8) " + ")
 9994     # var index/edx: (addr var) = inouts[1]
 9995     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9996     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
 9997     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9998     89/<- %edx 0/r32/eax
 9999     # if index->register
10000     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
10001     {
10002       0f 84/jump-if-= break/disp32
10003 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
10004       # if index is an int
10005       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10006       (is-simple-mu-type? %eax 1)  # int => eax
10007       3d/compare-eax-and 0/imm32/false
10008       {
10009         0f 84/jump-if-= break/disp32
10010 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
10011         # print index->register "<<" log2(size-of(element(base->type))) " + 4) "
10012         # . index->register "<<"
10013         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
10014         (write-buffered *(ebp+8) %eax)
10015         (write-buffered *(ebp+8) "<<")
10016         # . log2(size-of(element(base->type)))
10017         # TODO: ensure size is a power of 2
10018         (array-element-type-id %ebx)  # => eax
10019         (size-of-type-id %eax)  # => eax
10020         (num-shift-rights %eax)  # => eax
10021         (print-int32-buffered *(ebp+8) %eax)
10022         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
10023       }
10024       # if index->type is any other atom, abort
10025       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10026       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
10027       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
10028       # if index has type (offset ...)
10029       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
10030       (is-simple-mu-type? %eax 7)  # => eax
10031       3d/compare-eax-and 0/imm32/false
10032       {
10033         0f 84/jump-if-= break/disp32
10034         # print index->register
10035 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
10036         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
10037         (write-buffered *(ebp+8) %eax)
10038       }
10039 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
10040       (write-buffered *(ebp+8) " + 4) ")
10041       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
10042     }
10043     # otherwise if index is a literal
10044     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10045     (is-simple-mu-type? %eax 0)  # => eax
10046     3d/compare-eax-and 0/imm32/false
10047     {
10048       0f 84/jump-if-= break/disp32
10049 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
10050       # var index-value/edx: int = parse-hex-int(index->name)
10051       (lookup *edx *(edx+4))  # Var-name Var-name => eax
10052       (parse-hex-int %eax)  # => eax
10053       89/<- %edx 0/r32/eax
10054       # offset = idx-value * size-of(element(base->type))
10055       (array-element-type-id %ebx)  # => eax
10056       (size-of-type-id %eax)  # => eax
10057       f7 4/subop/multiply-into-eax %edx  # clobbers edx
10058       # offset += 4 for array size
10059       05/add-to-eax 4/imm32
10060       # TODO: check edx for overflow
10061       # print offset
10062       (print-int32-buffered *(ebp+8) %eax)
10063       (write-buffered *(ebp+8) ") ")
10064       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
10065     }
10066     # otherwise abort
10067     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
10068 $translate-mu-index-stmt-with-array-in-register:emit-output:
10069     # outputs[0] "/r32"
10070     8b/-> *(ebp+0xc) 1/r32/ecx
10071     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10072     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10073     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10074     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10075     (print-int32-buffered *(ebp+8) *eax)
10076     (write-buffered *(ebp+8) "/r32\n")
10077 $translate-mu-index-stmt-with-array-in-register:end:
10078     # . restore registers
10079     5b/pop-to-ebx
10080     5a/pop-to-edx
10081     59/pop-to-ecx
10082     58/pop-to-eax
10083     # . epilogue
10084     89/<- %esp 5/r32/ebp
10085     5d/pop-to-ebp
10086     c3/return
10087 
10088 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
10089     # . prologue
10090     55/push-ebp
10091     89/<- %ebp 4/r32/esp
10092     # . save registers
10093     50/push-eax
10094     51/push-ecx
10095     52/push-edx
10096     53/push-ebx
10097     #
10098     (emit-indent *(ebp+8) *Curr-block-depth)
10099     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
10100     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
10101     8b/-> *(ebp+0xc) 0/r32/eax
10102     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10103     89/<- %edx 0/r32/eax
10104     # var base/ecx: (addr var) = lookup(curr->value)
10105     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10106     89/<- %ecx 0/r32/eax
10107     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
10108     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
10109     # var index/edx: (handle var) = curr2->value
10110     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10111     89/<- %edx 0/r32/eax
10112     # if index->register
10113     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
10114     {
10115       0f 84/jump-if-= break/disp32
10116 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
10117       # if index is an int
10118       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10119       (is-simple-mu-type? %eax 1)  # int => eax
10120       3d/compare-eax-and 0/imm32/false
10121       {
10122         0f 84/jump-if-= break/disp32
10123 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
10124         # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4
10125         # . inouts[1]->register "<<"
10126         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
10127         (write-buffered *(ebp+8) %eax)
10128         (write-buffered *(ebp+8) "<<")
10129         # . log2(size-of(element(base)))
10130         # TODO: ensure size is a power of 2
10131         (array-element-type-id %ecx)  # => eax
10132         (size-of-type-id %eax)  # => eax
10133         (num-shift-rights %eax)  # => eax
10134         (print-int32-buffered *(ebp+8) %eax)
10135         #
10136         (write-buffered *(ebp+8) " + ")
10137         #
10138         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
10139         05/add-to-eax 4/imm32  # for array length
10140         (print-int32-buffered *(ebp+8) %eax)
10141         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
10142       }
10143       # if index->type is any other atom, abort
10144       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10145       81 7/subop/compare *eax 0/imm32/false  # Tree-is-atom
10146       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
10147       # if index has type (offset ...)
10148       (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
10149       (is-simple-mu-type? %eax 7)  # => eax
10150       3d/compare-eax-and 0/imm32/false
10151       {
10152         0f 84/jump-if-= break/disp32
10153         # print index->register
10154 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
10155         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
10156         (write-buffered *(ebp+8) %eax)
10157       }
10158 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
10159       (write-buffered *(ebp+8) ") ")
10160       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
10161     }
10162     # otherwise if index is a literal
10163     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
10164     (is-simple-mu-type? %eax 0)  # => eax
10165     3d/compare-eax-and 0/imm32/false
10166     {
10167       0f 84/jump-if-= break/disp32
10168 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
10169       # var idx-value/edx: int = parse-hex-int(index->name)
10170       (lookup *edx *(edx+4))  # Var-name Var-name => eax
10171       (parse-hex-int %eax)  # Var-name => eax
10172       89/<- %edx 0/r32/eax
10173       # offset = idx-value * size-of(element-type(base->type))
10174       (array-element-type-id %ecx)  # => eax
10175       (size-of-type-id %eax)  # => eax
10176       f7 4/subop/multiply-into-eax %edx  # clobbers edx
10177       # offset += base->offset
10178       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
10179       # offset += 4 for array size
10180       05/add-to-eax 4/imm32
10181       # TODO: check edx for overflow
10182       # print offset
10183       (print-int32-buffered *(ebp+8) %eax)
10184       (write-buffered *(ebp+8) ") ")
10185       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
10186     }
10187     # otherwise abort
10188     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
10189 $translate-mu-index-stmt-with-array-on-stack:emit-output:
10190     # outputs[0] "/r32"
10191     8b/-> *(ebp+0xc) 0/r32/eax
10192     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10193     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10194     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10195     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10196     (print-int32-buffered *(ebp+8) *eax)
10197     (write-buffered *(ebp+8) "/r32\n")
10198 $translate-mu-index-stmt-with-array-on-stack:end:
10199     # . restore registers
10200     5b/pop-to-ebx
10201     5a/pop-to-edx
10202     59/pop-to-ecx
10203     58/pop-to-eax
10204     # . epilogue
10205     89/<- %esp 5/r32/ebp
10206     5d/pop-to-ebp
10207     c3/return
10208 
10209 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
10210     # . prologue
10211     55/push-ebp
10212     89/<- %ebp 4/r32/esp
10213     # . save registers
10214     50/push-eax
10215     51/push-ecx
10216     52/push-edx
10217     53/push-ebx
10218     #
10219     (emit-indent *(ebp+8) *Curr-block-depth)
10220     (write-buffered *(ebp+8) "69/multiply")
10221     # ecx = stmt
10222     8b/-> *(ebp+0xc) 1/r32/ecx
10223     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
10224     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10225     89/<- %ebx 0/r32/eax
10226 $translate-mu-compute-index-stmt:emit-index:
10227     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
10228     (emit-subx-var-as-rm32 *(ebp+8) %eax)
10229     (write-buffered *(ebp+8) Space)
10230 $translate-mu-compute-index-stmt:emit-elem-size:
10231     # var base/ebx: (addr var)
10232     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
10233     89/<- %ebx 0/r32/eax
10234     # print size-of(element(base->type))
10235     (array-element-type-id %ebx)  # => eax
10236     (size-of-type-id %eax)  # => eax
10237     (print-int32-buffered *(ebp+8) %eax)
10238     (write-buffered *(ebp+8) "/imm32 ")
10239 $translate-mu-compute-index-stmt:emit-output:
10240     # outputs[0] "/r32"
10241     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10242     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10243     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10244     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10245     (print-int32-buffered *(ebp+8) *eax)
10246     (write-buffered *(ebp+8) "/r32\n")
10247 $translate-mu-compute-index-stmt:end:
10248     # . restore registers
10249     5b/pop-to-ebx
10250     5a/pop-to-edx
10251     59/pop-to-ecx
10252     58/pop-to-eax
10253     # . epilogue
10254     89/<- %esp 5/r32/ebp
10255     5d/pop-to-ebp
10256     c3/return
10257 
10258 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
10259     # . prologue
10260     55/push-ebp
10261     89/<- %ebp 4/r32/esp
10262     # . save registers
10263     50/push-eax
10264     51/push-ecx
10265     52/push-edx
10266     #
10267     (emit-indent *(ebp+8) *Curr-block-depth)
10268     (write-buffered *(ebp+8) "8d/copy-address ")
10269     # ecx = stmt
10270     8b/-> *(ebp+0xc) 1/r32/ecx
10271     # var offset/edx: int = get offset of stmt
10272     (mu-get-offset %ecx)  # => eax
10273     89/<- %edx 0/r32/eax
10274     # var base/eax: (addr var) = stmt->inouts->value
10275     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10276     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10277     # if base is in a register
10278     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
10279     {
10280       0f 84/jump-if-= break/disp32
10281 $translate-mu-get-stmt:emit-register-input:
10282       # emit "*(" base->register " + " offset ") "
10283       (write-buffered *(ebp+8) "*(")
10284       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10285       (write-buffered *(ebp+8) %eax)
10286       (write-buffered *(ebp+8) " + ")
10287       (print-int32-buffered *(ebp+8) %edx)
10288       (write-buffered *(ebp+8) ") ")
10289       e9/jump $translate-mu-get-stmt:emit-output/disp32
10290     }
10291     # otherwise base is on the stack
10292     {
10293 $translate-mu-get-stmt:emit-stack-input:
10294       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
10295       (write-buffered *(ebp+8) "*(ebp+")
10296       03/add *(eax+0x14) 2/r32/edx  # Var-offset
10297       (print-int32-buffered *(ebp+8) %edx)
10298       (write-buffered *(ebp+8) ") ")
10299       eb/jump $translate-mu-get-stmt:emit-output/disp8
10300     }
10301 $translate-mu-get-stmt:emit-output:
10302     # var output/eax: (addr var) = stmt->outputs->value
10303     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
10304     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10305     # emit offset->register "/r32"
10306     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
10307     (get Registers %eax 0xc "Registers")  # => eax: (addr int)
10308     (print-int32-buffered *(ebp+8) *eax)
10309     (write-buffered *(ebp+8) "/r32\n")
10310 $translate-mu-get-stmt:end:
10311     # . restore registers
10312     5a/pop-to-edx
10313     59/pop-to-ecx
10314     58/pop-to-eax
10315     # . epilogue
10316     89/<- %esp 5/r32/ebp
10317     5d/pop-to-ebp
10318     c3/return
10319 
10320 array-element-type-id:  # v: (addr var) -> result/eax: type-id
10321     # precondition: n is positive
10322     # . prologue
10323     55/push-ebp
10324     89/<- %ebp 4/r32/esp
10325     #
10326     8b/-> *(ebp+8) 0/r32/eax
10327     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
10328     # TODO: ensure type->left is 'addr'
10329     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
10330     # TODO: ensure that type->right is non-null
10331     # TODO: ensure that type->right->left is 'array'
10332     (lookup *(eax+0xc) *(eax+0x10))  # Tree-right Tree-right => eax
10333     # TODO: ensure that type->right->right is non-null
10334     (lookup *(eax+4) *(eax+8))  # Tree-left Tree-left => eax
10335     8b/-> *(eax+4) 0/r32/eax  # Tree-value
10336 $array-element-type-id:end:
10337     # . epilogue
10338     89/<- %esp 5/r32/ebp
10339     5d/pop-to-ebp
10340     c3/return
10341 
10342 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
10343     # precondition: n is positive
10344     # . prologue
10345     55/push-ebp
10346     89/<- %ebp 4/r32/esp
10347     # eax = n
10348     8b/-> *(ebp+8) 0/r32/eax
10349     # if (n < 0) abort
10350     3d/compare-eax-with 0/imm32
10351     0f 8c/jump-if-< $power-of-2?:abort/disp32
10352     # var tmp/eax: int = n-1
10353     48/decrement-eax
10354     # var tmp2/eax: int = n & tmp
10355     23/and-> *(ebp+8) 0/r32/eax
10356     # return (tmp2 == 0)
10357     3d/compare-eax-and 0/imm32
10358     0f 94/set-byte-if-= %al
10359     81 4/subop/and %eax 0xff/imm32
10360 $power-of-2?:end:
10361     # . epilogue
10362     89/<- %esp 5/r32/ebp
10363     5d/pop-to-ebp
10364     c3/return
10365 
10366 $power-of-2?:abort:
10367     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
10368     (flush *(ebp+0xc))
10369     (stop *(ebp+0x10) 1)
10370     # never gets here
10371 
10372 num-shift-rights:  # n: int -> result/eax: int
10373     # precondition: n is a positive power of 2
10374     # . prologue
10375     55/push-ebp
10376     89/<- %ebp 4/r32/esp
10377     # . save registers
10378     51/push-ecx
10379     # var curr/ecx: int = n
10380     8b/-> *(ebp+8) 1/r32/ecx
10381     # result = 0
10382     b8/copy-to-eax 0/imm32
10383     {
10384       # if (curr <= 1) break
10385       81 7/subop/compare %ecx 1/imm32
10386       7e/jump-if-<= break/disp8
10387       40/increment-eax
10388       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
10389       eb/jump loop/disp8
10390     }
10391 $num-shift-rights:end:
10392     # . restore registers
10393     59/pop-to-ecx
10394     # . epilogue
10395     89/<- %esp 5/r32/ebp
10396     5d/pop-to-ebp
10397     c3/return
10398 
10399 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
10400     # . prologue
10401     55/push-ebp
10402     89/<- %ebp 4/r32/esp
10403     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
10404     8b/-> *(ebp+8) 0/r32/eax
10405     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
10406     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
10407     # var output-var/eax: (addr var) = second-inout->value
10408     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
10409 #?     (write-buffered Stderr "mu-get-offset: ")
10410 #?     (print-int32-buffered Stderr %eax)
10411 #?     (write-buffered Stderr " name: ")
10412 #?     50/push-eax
10413 #?     (lookup *eax *(eax+4))  # Var-name
10414 #?     (write-buffered Stderr %eax)
10415 #?     58/pop-to-eax
10416 #?     (write-buffered Stderr Newline)
10417 #?     (flush Stderr)
10418     # return output-var->stack-offset
10419     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
10420 #?     (write-buffered Stderr "=> ")
10421 #?     (print-int32-buffered Stderr %eax)
10422 #?     (write-buffered Stderr Newline)
10423 #?     (flush Stderr)
10424 $emit-get-offset:end:
10425     # . epilogue
10426     89/<- %esp 5/r32/ebp
10427     5d/pop-to-ebp
10428     c3/return
10429 
10430 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn-outputs: (addr list var), err: (addr buffered-file), ed: (addr exit-descriptor)
10431     # . prologue
10432     55/push-ebp
10433     89/<- %ebp 4/r32/esp
10434     # . save registers
10435     50/push-eax
10436     51/push-ecx
10437     56/push-esi
10438     # esi = block
10439     8b/-> *(ebp+0xc) 6/r32/esi
10440     # block->var->block-depth = *Curr-block-depth
10441     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
10442     8b/-> *Curr-block-depth 1/r32/ecx
10443     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
10444     # var stmts/eax: (addr list stmt) = lookup(block->statements)
10445     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
10446     #
10447     {
10448 $emit-subx-block:check-empty:
10449       3d/compare-eax-and 0/imm32
10450       0f 84/jump-if-= break/disp32
10451       (emit-indent *(ebp+8) *Curr-block-depth)
10452       (write-buffered *(ebp+8) "{\n")
10453       # var v/ecx: (addr var) = lookup(block->var)
10454       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
10455       89/<- %ecx 0/r32/eax
10456       #
10457       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10458       (write-buffered *(ebp+8) %eax)
10459       (write-buffered *(ebp+8) ":loop:\n")
10460       ff 0/subop/increment *Curr-block-depth
10461       (push *(ebp+0x10) *(esi+0xc))  # Block-var
10462       (push *(ebp+0x10) *(esi+0x10))  # Block-var
10463       (push *(ebp+0x10) 0)  # false
10464       # emit block->statements
10465       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
10466       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
10467       (pop *(ebp+0x10))  # => eax
10468       (pop *(ebp+0x10))  # => eax
10469       (pop *(ebp+0x10))  # => eax
10470       ff 1/subop/decrement *Curr-block-depth
10471       (emit-indent *(ebp+8) *Curr-block-depth)
10472       (write-buffered *(ebp+8) "}\n")
10473       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
10474       (write-buffered *(ebp+8) %eax)
10475       (write-buffered *(ebp+8) ":break:\n")
10476     }
10477 $emit-subx-block:end:
10478     # . restore registers
10479     5e/pop-to-esi
10480     59/pop-to-ecx
10481     58/pop-to-eax
10482     # . epilogue
10483     89/<- %esp 5/r32/ebp
10484     5d/pop-to-ebp
10485     c3/return
10486 
10487 # Primitives supported
10488 # See mu_instructions for a summary of this linked-list data structure.
10489 #
10490 # For each operation, put variants with hard-coded registers before flexible ones.
10491 #
10492 # Unfortunately, our restrictions on addresses require that various fields in
10493 # primitives be handles, which complicates these definitions.
10494 #   - we need to insert dummy fields all over the place for fake alloc-ids
10495 #   - we can't use our syntax sugar of quoted literals for string fields
10496 #
10497 # Fake alloc-ids are needed because our type definitions up top require
10498 # handles but it's clearer to statically allocate these long-lived objects.
10499 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
10500 #
10501 # Every 'object' below starts with a fake alloc-id. It may also contain other
10502 # fake alloc-ids for various handle fields.
10503 #
10504 # I think of objects starting with a fake alloc-id as having type 'payload'.
10505 # It's not really intended to be created dynamically; for that use `allocate`
10506 # as usual.
10507 #
10508 # Idea for a notation to simplify such definitions:
10509 #   _Primitive-increment-eax:  # (payload primitive)
10510 #     0x11/alloc-id:fake:payload
10511 #     0x11 @(0x11 "increment")  # name
10512 #     0 0                       # inouts
10513 #     0x11 @(0x11/payload
10514 #            0x11 @(0x11/payload  # List-value
10515 #                   0 0             # Var-name
10516 #                   0x11 @(0x11     # Var-type
10517 #                          1/is-atom
10518 #                          1/value 0/unused   # Tree-left
10519 #                          0 0                # Tree-right
10520 #                         )
10521 #                   1               # block-depth
10522 #                   0               # stack-offset
10523 #                   0x11 @(0x11 "eax")  # Var-register
10524 #                  )
10525 #            0 0)                 # List-next
10526 #     ...
10527 #     _Primitive-increment-ecx/imm32/next
10528 #   ...
10529 # Awfully complex and non-obvious. But also clearly signals there's something
10530 # to learn here, so may be worth trying.
10531 #
10532 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
10533 #
10534 # For now we'll continue to just use comments and manually ensure they stay up
10535 # to date.
10536 == data
10537 Primitives:  # (addr primitive)
10538 # - increment/decrement
10539 _Primitive-increment-eax:  # (addr primitive)
10540     # var/eax <- increment => 40/increment-eax
10541     0x11/imm32/alloc-id:fake
10542     _string-increment/imm32/name
10543     0/imm32/no-inouts
10544     0/imm32/no-inouts
10545     0x11/imm32/alloc-id:fake
10546     Single-int-var-in-eax/imm32/outputs
10547     0x11/imm32/alloc-id:fake
10548     _string_40_increment_eax/imm32/subx-name
10549     0/imm32/no-rm32
10550     0/imm32/no-r32
10551     0/imm32/no-imm32
10552     0/imm32/no-disp32
10553     0/imm32/output-is-write-only
10554     0x11/imm32/alloc-id:fake
10555     _Primitive-increment-ecx/imm32/next
10556 _Primitive-increment-ecx:  # (payload primitive)
10557     0x11/imm32/alloc-id:fake:payload
10558     # var/ecx <- increment => 41/increment-ecx
10559     0x11/imm32/alloc-id:fake
10560     _string-increment/imm32/name
10561     0/imm32/no-inouts
10562     0/imm32/no-inouts
10563     0x11/imm32/alloc-id:fake
10564     Single-int-var-in-ecx/imm32/outputs
10565     0x11/imm32/alloc-id:fake
10566     _string_41_increment_ecx/imm32/subx-name
10567     0/imm32/no-rm32
10568     0/imm32/no-r32
10569     0/imm32/no-imm32
10570     0/imm32/no-disp32
10571     0/imm32/output-is-write-only
10572     0x11/imm32/alloc-id:fake
10573     _Primitive-increment-edx/imm32/next
10574 _Primitive-increment-edx:  # (payload primitive)
10575     0x11/imm32/alloc-id:fake:payload
10576     # var/edx <- increment => 42/increment-edx
10577     0x11/imm32/alloc-id:fake
10578     _string-increment/imm32/name
10579     0/imm32/no-inouts
10580     0/imm32/no-inouts
10581     0x11/imm32/alloc-id:fake
10582     Single-int-var-in-edx/imm32/outputs
10583     0x11/imm32/alloc-id:fake
10584     _string_42_increment_edx/imm32/subx-name
10585     0/imm32/no-rm32
10586     0/imm32/no-r32
10587     0/imm32/no-imm32
10588     0/imm32/no-disp32
10589     0/imm32/output-is-write-only
10590     0x11/imm32/alloc-id:fake
10591     _Primitive-increment-ebx/imm32/next
10592 _Primitive-increment-ebx:  # (payload primitive)
10593     0x11/imm32/alloc-id:fake:payload
10594     # var/ebx <- increment => 43/increment-ebx
10595     0x11/imm32/alloc-id:fake
10596     _string-increment/imm32/name
10597     0/imm32/no-inouts
10598     0/imm32/no-inouts
10599     0x11/imm32/alloc-id:fake
10600     Single-int-var-in-ebx/imm32/outputs
10601     0x11/imm32/alloc-id:fake
10602     _string_43_increment_ebx/imm32/subx-name
10603     0/imm32/no-rm32
10604     0/imm32/no-r32
10605     0/imm32/no-imm32
10606     0/imm32/no-disp32
10607     0/imm32/output-is-write-only
10608     0x11/imm32/alloc-id:fake
10609     _Primitive-increment-esi/imm32/next
10610 _Primitive-increment-esi:  # (payload primitive)
10611     0x11/imm32/alloc-id:fake:payload
10612     # var/esi <- increment => 46/increment-esi
10613     0x11/imm32/alloc-id:fake
10614     _string-increment/imm32/name
10615     0/imm32/no-inouts
10616     0/imm32/no-inouts
10617     0x11/imm32/alloc-id:fake
10618     Single-int-var-in-esi/imm32/outputs
10619     0x11/imm32/alloc-id:fake
10620     _string_46_increment_esi/imm32/subx-name
10621     0/imm32/no-rm32
10622     0/imm32/no-r32
10623     0/imm32/no-imm32
10624     0/imm32/no-disp32
10625     0/imm32/output-is-write-only
10626     0x11/imm32/alloc-id:fake
10627     _Primitive-increment-edi/imm32/next
10628 _Primitive-increment-edi:  # (payload primitive)
10629     0x11/imm32/alloc-id:fake:payload
10630     # var/edi <- increment => 47/increment-edi
10631     0x11/imm32/alloc-id:fake
10632     _string-increment/imm32/name
10633     0/imm32/no-inouts
10634     0/imm32/no-inouts
10635     0x11/imm32/alloc-id:fake
10636     Single-int-var-in-edi/imm32/outputs
10637     0x11/imm32/alloc-id:fake
10638     _string_47_increment_edi/imm32/subx-name
10639     0/imm32/no-rm32
10640     0/imm32/no-r32
10641     0/imm32/no-imm32
10642     0/imm32/no-disp32
10643     0/imm32/output-is-write-only
10644     0x11/imm32/alloc-id:fake
10645     _Primitive-decrement-eax/imm32/next
10646 _Primitive-decrement-eax:  # (payload primitive)
10647     0x11/imm32/alloc-id:fake:payload
10648     # var/eax <- decrement => 48/decrement-eax
10649     0x11/imm32/alloc-id:fake
10650     _string-decrement/imm32/name
10651     0/imm32/no-inouts
10652     0/imm32/no-inouts
10653     0x11/imm32/alloc-id:fake
10654     Single-int-var-in-eax/imm32/outputs
10655     0x11/imm32/alloc-id:fake
10656     _string_48_decrement_eax/imm32/subx-name
10657     0/imm32/no-rm32
10658     0/imm32/no-r32
10659     0/imm32/no-imm32
10660     0/imm32/no-disp32
10661     0/imm32/output-is-write-only
10662     0x11/imm32/alloc-id:fake
10663     _Primitive-decrement-ecx/imm32/next
10664 _Primitive-decrement-ecx:  # (payload primitive)
10665     0x11/imm32/alloc-id:fake:payload
10666     # var/ecx <- decrement => 49/decrement-ecx
10667     0x11/imm32/alloc-id:fake
10668     _string-decrement/imm32/name
10669     0/imm32/no-inouts
10670     0/imm32/no-inouts
10671     0x11/imm32/alloc-id:fake
10672     Single-int-var-in-ecx/imm32/outputs
10673     0x11/imm32/alloc-id:fake
10674     _string_49_decrement_ecx/imm32/subx-name
10675     0/imm32/no-rm32
10676     0/imm32/no-r32
10677     0/imm32/no-imm32
10678     0/imm32/no-disp32
10679     0/imm32/output-is-write-only
10680     0x11/imm32/alloc-id:fake
10681     _Primitive-decrement-edx/imm32/next
10682 _Primitive-decrement-edx:  # (payload primitive)
10683     0x11/imm32/alloc-id:fake:payload
10684     # var/edx <- decrement => 4a/decrement-edx
10685     0x11/imm32/alloc-id:fake
10686     _string-decrement/imm32/name
10687     0/imm32/no-inouts
10688     0/imm32/no-inouts
10689     0x11/imm32/alloc-id:fake
10690     Single-int-var-in-edx/imm32/outputs
10691     0x11/imm32/alloc-id:fake
10692     _string_4a_decrement_edx/imm32/subx-name
10693     0/imm32/no-rm32
10694     0/imm32/no-r32
10695     0/imm32/no-imm32
10696     0/imm32/no-disp32
10697     0/imm32/output-is-write-only
10698     0x11/imm32/alloc-id:fake
10699     _Primitive-decrement-ebx/imm32/next
10700 _Primitive-decrement-ebx:  # (payload primitive)
10701     0x11/imm32/alloc-id:fake:payload
10702     # var/ebx <- decrement => 4b/decrement-ebx
10703     0x11/imm32/alloc-id:fake
10704     _string-decrement/imm32/name
10705     0/imm32/no-inouts
10706     0/imm32/no-inouts
10707     0x11/imm32/alloc-id:fake
10708     Single-int-var-in-ebx/imm32/outputs
10709     0x11/imm32/alloc-id:fake
10710     _string_4b_decrement_ebx/imm32/subx-name
10711     0/imm32/no-rm32
10712     0/imm32/no-r32
10713     0/imm32/no-imm32
10714     0/imm32/no-disp32
10715     0/imm32/output-is-write-only
10716     0x11/imm32/alloc-id:fake
10717     _Primitive-decrement-esi/imm32/next
10718 _Primitive-decrement-esi:  # (payload primitive)
10719     0x11/imm32/alloc-id:fake:payload
10720     # var/esi <- decrement => 4e/decrement-esi
10721     0x11/imm32/alloc-id:fake
10722     _string-decrement/imm32/name
10723     0/imm32/no-inouts
10724     0/imm32/no-inouts
10725     0x11/imm32/alloc-id:fake
10726     Single-int-var-in-esi/imm32/outputs
10727     0x11/imm32/alloc-id:fake
10728     _string_4e_decrement_esi/imm32/subx-name
10729     0/imm32/no-rm32
10730     0/imm32/no-r32
10731     0/imm32/no-imm32
10732     0/imm32/no-disp32
10733     0/imm32/output-is-write-only
10734     0x11/imm32/alloc-id:fake
10735     _Primitive-decrement-edi/imm32/next
10736 _Primitive-decrement-edi:  # (payload primitive)
10737     0x11/imm32/alloc-id:fake:payload
10738     # var/edi <- decrement => 4f/decrement-edi
10739     0x11/imm32/alloc-id:fake
10740     _string-decrement/imm32/name
10741     0/imm32/no-inouts
10742     0/imm32/no-inouts
10743     0x11/imm32/alloc-id:fake
10744     Single-int-var-in-edi/imm32/outputs
10745     0x11/imm32/alloc-id:fake
10746     _string_4f_decrement_edi/imm32/subx-name
10747     0/imm32/no-rm32
10748     0/imm32/no-r32
10749     0/imm32/no-imm32
10750     0/imm32/no-disp32
10751     0/imm32/output-is-write-only
10752     0x11/imm32/alloc-id:fake
10753     _Primitive-increment-mem/imm32/next
10754 _Primitive-increment-mem:  # (payload primitive)
10755     0x11/imm32/alloc-id:fake:payload
10756     # increment var => ff 0/subop/increment *(ebp+__)
10757     0x11/imm32/alloc-id:fake
10758     _string-increment/imm32/name
10759     0x11/imm32/alloc-id:fake
10760     Single-int-var-in-mem/imm32/inouts
10761     0/imm32/no-outputs
10762     0/imm32/no-outputs
10763     0x11/imm32/alloc-id:fake
10764     _string_ff_subop_increment/imm32/subx-name
10765     1/imm32/rm32-is-first-inout
10766     0/imm32/no-r32
10767     0/imm32/no-imm32
10768     0/imm32/no-disp32
10769     0/imm32/output-is-write-only
10770     0x11/imm32/alloc-id:fake
10771     _Primitive-increment-reg/imm32/next
10772 _Primitive-increment-reg:  # (payload primitive)
10773     0x11/imm32/alloc-id:fake:payload
10774     # var/reg <- increment => ff 0/subop/increment %__
10775     0x11/imm32/alloc-id:fake
10776     _string-increment/imm32/name
10777     0/imm32/no-inouts
10778     0/imm32/no-inouts
10779     0x11/imm32/alloc-id:fake
10780     Single-int-var-in-some-register/imm32/outputs
10781     0x11/imm32/alloc-id:fake
10782     _string_ff_subop_increment/imm32/subx-name
10783     3/imm32/rm32-is-first-output
10784     0/imm32/no-r32
10785     0/imm32/no-imm32
10786     0/imm32/no-disp32
10787     0/imm32/output-is-write-only
10788     0x11/imm32/alloc-id:fake
10789     _Primitive-decrement-mem/imm32/next
10790 _Primitive-decrement-mem:  # (payload primitive)
10791     0x11/imm32/alloc-id:fake:payload
10792     # decrement var => ff 1/subop/decrement *(ebp+__)
10793     0x11/imm32/alloc-id:fake
10794     _string-decrement/imm32/name
10795     0x11/imm32/alloc-id:fake
10796     Single-int-var-in-mem/imm32/inouts
10797     0/imm32/no-outputs
10798     0/imm32/no-outputs
10799     0x11/imm32/alloc-id:fake
10800     _string_ff_subop_decrement/imm32/subx-name
10801     1/imm32/rm32-is-first-inout
10802     0/imm32/no-r32
10803     0/imm32/no-imm32
10804     0/imm32/no-disp32
10805     0/imm32/output-is-write-only
10806     0x11/imm32/alloc-id:fake
10807     _Primitive-decrement-reg/imm32/next
10808 _Primitive-decrement-reg:  # (payload primitive)
10809     0x11/imm32/alloc-id:fake:payload
10810     # var/reg <- decrement => ff 1/subop/decrement %__
10811     0x11/imm32/alloc-id:fake
10812     _string-decrement/imm32/name
10813     0/imm32/no-inouts
10814     0/imm32/no-inouts
10815     0x11/imm32/alloc-id:fake
10816     Single-int-var-in-some-register/imm32/outputs
10817     0x11/imm32/alloc-id:fake
10818     _string_ff_subop_decrement/imm32/subx-name
10819     3/imm32/rm32-is-first-output
10820     0/imm32/no-r32
10821     0/imm32/no-imm32
10822     0/imm32/no-disp32
10823     0/imm32/output-is-write-only
10824     0x11/imm32/alloc-id:fake
10825     _Primitive-add-to-eax/imm32/next
10826 # - add
10827 _Primitive-add-to-eax:  # (payload primitive)
10828     0x11/imm32/alloc-id:fake:payload
10829     # var/eax <- add lit => 05/add-to-eax lit/imm32
10830     0x11/imm32/alloc-id:fake
10831     _string-add/imm32/name
10832     0x11/imm32/alloc-id:fake
10833     Single-lit-var/imm32/inouts
10834     0x11/imm32/alloc-id:fake
10835     Single-int-var-in-eax/imm32/outputs
10836     0x11/imm32/alloc-id:fake
10837     _string_05_add_to_eax/imm32/subx-name
10838     0/imm32/no-rm32
10839     0/imm32/no-r32
10840     1/imm32/imm32-is-first-inout
10841     0/imm32/no-disp32
10842     0/imm32/output-is-write-only
10843     0x11/imm32/alloc-id:fake
10844     _Primitive-add-reg-to-reg/imm32/next
10845 _Primitive-add-reg-to-reg:  # (payload primitive)
10846     0x11/imm32/alloc-id:fake:payload
10847     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
10848     0x11/imm32/alloc-id:fake
10849     _string-add/imm32/name
10850     0x11/imm32/alloc-id:fake
10851     Single-int-var-in-some-register/imm32/inouts
10852     0x11/imm32/alloc-id:fake
10853     Single-int-var-in-some-register/imm32/outputs
10854     0x11/imm32/alloc-id:fake
10855     _string_01_add_to/imm32/subx-name
10856     3/imm32/rm32-is-first-output
10857     1/imm32/r32-is-first-inout
10858     0/imm32/no-imm32
10859     0/imm32/no-disp32
10860     0/imm32/output-is-write-only
10861     0x11/imm32/alloc-id:fake
10862     _Primitive-add-reg-to-mem/imm32/next
10863 _Primitive-add-reg-to-mem:  # (payload primitive)
10864     0x11/imm32/alloc-id:fake:payload
10865     # add-to var1 var2/reg => 01/add-to var1 var2/r32
10866     0x11/imm32/alloc-id:fake
10867     _string-add-to/imm32/name
10868     0x11/imm32/alloc-id:fake
10869     Two-args-int-stack-int-reg/imm32/inouts
10870     0/imm32/no-outputs
10871     0/imm32/no-outputs
10872     0x11/imm32/alloc-id:fake
10873     _string_01_add_to/imm32/subx-name
10874     1/imm32/rm32-is-first-inout
10875     2/imm32/r32-is-second-inout
10876     0/imm32/no-imm32
10877     0/imm32/no-disp32
10878     0/imm32/output-is-write-only
10879     0x11/imm32/alloc-id:fake
10880     _Primitive-add-mem-to-reg/imm32/next
10881 _Primitive-add-mem-to-reg:  # (payload primitive)
10882     0x11/imm32/alloc-id:fake:payload
10883     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
10884     0x11/imm32/alloc-id:fake
10885     _string-add/imm32/name
10886     0x11/imm32/alloc-id:fake
10887     Single-int-var-in-mem/imm32/inouts
10888     0x11/imm32/alloc-id:fake
10889     Single-int-var-in-some-register/imm32/outputs
10890     0x11/imm32/alloc-id:fake
10891     _string_03_add/imm32/subx-name
10892     1/imm32/rm32-is-first-inout
10893     3/imm32/r32-is-first-output
10894     0/imm32/no-imm32
10895     0/imm32/no-disp32
10896     0/imm32/output-is-write-only
10897     0x11/imm32/alloc-id:fake
10898     _Primitive-add-lit-to-reg/imm32/next
10899 _Primitive-add-lit-to-reg:  # (payload primitive)
10900     0x11/imm32/alloc-id:fake:payload
10901     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
10902     0x11/imm32/alloc-id:fake
10903     _string-add/imm32/name
10904     0x11/imm32/alloc-id:fake
10905     Single-lit-var/imm32/inouts
10906     0x11/imm32/alloc-id:fake
10907     Single-int-var-in-some-register/imm32/outputs
10908     0x11/imm32/alloc-id:fake
10909     _string_81_subop_add/imm32/subx-name
10910     3/imm32/rm32-is-first-output
10911     0/imm32/no-r32
10912     1/imm32/imm32-is-first-inout
10913     0/imm32/no-disp32
10914     0/imm32/output-is-write-only
10915     0x11/imm32/alloc-id:fake
10916     _Primitive-add-lit-to-mem/imm32/next
10917 _Primitive-add-lit-to-mem:  # (payload primitive)
10918     0x11/imm32/alloc-id:fake:payload
10919     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
10920     0x11/imm32/alloc-id:fake
10921     _string-add-to/imm32/name
10922     0x11/imm32/alloc-id:fake
10923     Int-var-and-literal/imm32/inouts
10924     0/imm32/no-outputs
10925     0/imm32/no-outputs
10926     0x11/imm32/alloc-id:fake
10927     _string_81_subop_add/imm32/subx-name
10928     1/imm32/rm32-is-first-inout
10929     0/imm32/no-r32
10930     2/imm32/imm32-is-second-inout
10931     0/imm32/no-disp32
10932     0/imm32/output-is-write-only
10933     0x11/imm32/alloc-id:fake
10934     _Primitive-subtract-from-eax/imm32/next
10935 # - subtract
10936 _Primitive-subtract-from-eax:  # (payload primitive)
10937     0x11/imm32/alloc-id:fake:payload
10938     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
10939     0x11/imm32/alloc-id:fake
10940     _string-subtract/imm32/name
10941     0x11/imm32/alloc-id:fake
10942     Single-lit-var/imm32/inouts
10943     0x11/imm32/alloc-id:fake
10944     Single-int-var-in-eax/imm32/outputs
10945     0x11/imm32/alloc-id:fake
10946     _string_2d_subtract_from_eax/imm32/subx-name
10947     0/imm32/no-rm32
10948     0/imm32/no-r32
10949     1/imm32/imm32-is-first-inout
10950     0/imm32/no-disp32
10951     0/imm32/output-is-write-only
10952     0x11/imm32/alloc-id:fake
10953     _Primitive-subtract-reg-from-reg/imm32/next
10954 _Primitive-subtract-reg-from-reg:  # (payload primitive)
10955     0x11/imm32/alloc-id:fake:payload
10956     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
10957     0x11/imm32/alloc-id:fake
10958     _string-subtract/imm32/name
10959     0x11/imm32/alloc-id:fake
10960     Single-int-var-in-some-register/imm32/inouts
10961     0x11/imm32/alloc-id:fake
10962     Single-int-var-in-some-register/imm32/outputs
10963     0x11/imm32/alloc-id:fake
10964     _string_29_subtract_from/imm32/subx-name
10965     3/imm32/rm32-is-first-output
10966     1/imm32/r32-is-first-inout
10967     0/imm32/no-imm32
10968     0/imm32/no-disp32
10969     0/imm32/output-is-write-only
10970     0x11/imm32/alloc-id:fake
10971     _Primitive-subtract-reg-from-mem/imm32/next
10972 _Primitive-subtract-reg-from-mem:  # (payload primitive)
10973     0x11/imm32/alloc-id:fake:payload
10974     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
10975     0x11/imm32/alloc-id:fake
10976     _string-subtract-from/imm32/name
10977     0x11/imm32/alloc-id:fake
10978     Two-args-int-stack-int-reg/imm32/inouts
10979     0/imm32/no-outputs
10980     0/imm32/no-outputs
10981     0x11/imm32/alloc-id:fake
10982     _string_29_subtract_from/imm32/subx-name
10983     1/imm32/rm32-is-first-inout
10984     2/imm32/r32-is-second-inout
10985     0/imm32/no-imm32
10986     0/imm32/no-disp32
10987     0/imm32/output-is-write-only
10988     0x11/imm32/alloc-id:fake
10989     _Primitive-subtract-mem-from-reg/imm32/next
10990 _Primitive-subtract-mem-from-reg:  # (payload primitive)
10991     0x11/imm32/alloc-id:fake:payload
10992     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
10993     0x11/imm32/alloc-id:fake
10994     _string-subtract/imm32/name
10995     0x11/imm32/alloc-id:fake
10996     Single-int-var-in-mem/imm32/inouts
10997     0x11/imm32/alloc-id:fake
10998     Single-int-var-in-some-register/imm32/outputs
10999     0x11/imm32/alloc-id:fake
11000     _string_2b_subtract/imm32/subx-name
11001     1/imm32/rm32-is-first-inout
11002     3/imm32/r32-is-first-output
11003     0/imm32/no-imm32
11004     0/imm32/no-disp32
11005     0/imm32/output-is-write-only
11006     0x11/imm32/alloc-id:fake
11007     _Primitive-subtract-lit-from-reg/imm32/next
11008 _Primitive-subtract-lit-from-reg:  # (payload primitive)
11009     0x11/imm32/alloc-id:fake:payload
11010     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
11011     0x11/imm32/alloc-id:fake
11012     _string-subtract/imm32/name
11013     0x11/imm32/alloc-id:fake
11014     Single-lit-var/imm32/inouts
11015     0x11/imm32/alloc-id:fake
11016     Single-int-var-in-some-register/imm32/outputs
11017     0x11/imm32/alloc-id:fake
11018     _string_81_subop_subtract/imm32/subx-name
11019     3/imm32/rm32-is-first-output
11020     0/imm32/no-r32
11021     1/imm32/imm32-is-first-inout
11022     0/imm32/no-disp32
11023     0/imm32/output-is-write-only
11024     0x11/imm32/alloc-id:fake
11025     _Primitive-subtract-lit-from-mem/imm32/next
11026 _Primitive-subtract-lit-from-mem:  # (payload primitive)
11027     0x11/imm32/alloc-id:fake:payload
11028     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
11029     0x11/imm32/alloc-id:fake
11030     _string-subtract-from/imm32/name
11031     0x11/imm32/alloc-id:fake
11032     Int-var-and-literal/imm32/inouts
11033     0/imm32/no-outputs
11034     0/imm32/no-outputs
11035     0x11/imm32/alloc-id:fake
11036     _string_81_subop_subtract/imm32/subx-name
11037     1/imm32/rm32-is-first-inout
11038     0/imm32/no-r32
11039     2/imm32/imm32-is-first-inout
11040     0/imm32/no-disp32
11041     0/imm32/output-is-write-only
11042     0x11/imm32/alloc-id:fake
11043     _Primitive-and-with-eax/imm32/next
11044 # - and
11045 _Primitive-and-with-eax:  # (payload primitive)
11046     0x11/imm32/alloc-id:fake:payload
11047     # var/eax <- and lit => 25/and-with-eax lit/imm32
11048     0x11/imm32/alloc-id:fake
11049     _string-and/imm32/name
11050     0x11/imm32/alloc-id:fake
11051     Single-lit-var/imm32/inouts
11052     0x11/imm32/alloc-id:fake
11053     Single-int-var-in-eax/imm32/outputs
11054     0x11/imm32/alloc-id:fake
11055     _string_25_and_with_eax/imm32/subx-name
11056     0/imm32/no-rm32
11057     0/imm32/no-r32
11058     1/imm32/imm32-is-first-inout
11059     0/imm32/no-disp32
11060     0/imm32/output-is-write-only
11061     0x11/imm32/alloc-id:fake
11062     _Primitive-and-reg-with-reg/imm32/next
11063 _Primitive-and-reg-with-reg:  # (payload primitive)
11064     0x11/imm32/alloc-id:fake:payload
11065     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
11066     0x11/imm32/alloc-id:fake
11067     _string-and/imm32/name
11068     0x11/imm32/alloc-id:fake
11069     Single-int-var-in-some-register/imm32/inouts
11070     0x11/imm32/alloc-id:fake
11071     Single-int-var-in-some-register/imm32/outputs
11072     0x11/imm32/alloc-id:fake
11073     _string_21_and_with/imm32/subx-name
11074     3/imm32/rm32-is-first-output
11075     1/imm32/r32-is-first-inout
11076     0/imm32/no-imm32
11077     0/imm32/no-disp32
11078     0/imm32/output-is-write-only
11079     0x11/imm32/alloc-id:fake
11080     _Primitive-and-reg-with-mem/imm32/next
11081 _Primitive-and-reg-with-mem:  # (payload primitive)
11082     0x11/imm32/alloc-id:fake:payload
11083     # and-with var1 var2/reg => 21/and-with var1 var2/r32
11084     0x11/imm32/alloc-id:fake
11085     _string-and-with/imm32/name
11086     0x11/imm32/alloc-id:fake
11087     Two-args-int-stack-int-reg/imm32/inouts
11088     0/imm32/no-outputs
11089     0/imm32/no-outputs
11090     0x11/imm32/alloc-id:fake
11091     _string_21_and_with/imm32/subx-name
11092     1/imm32/rm32-is-first-inout
11093     2/imm32/r32-is-second-inout
11094     0/imm32/no-imm32
11095     0/imm32/no-disp32
11096     0/imm32/output-is-write-only
11097     0x11/imm32/alloc-id:fake
11098     _Primitive-and-mem-with-reg/imm32/next
11099 _Primitive-and-mem-with-reg:  # (payload primitive)
11100     0x11/imm32/alloc-id:fake:payload
11101     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
11102     0x11/imm32/alloc-id:fake
11103     _string-and/imm32/name
11104     0x11/imm32/alloc-id:fake
11105     Single-int-var-in-mem/imm32/inouts
11106     0x11/imm32/alloc-id:fake
11107     Single-int-var-in-some-register/imm32/outputs
11108     0x11/imm32/alloc-id:fake
11109     _string_23_and/imm32/subx-name
11110     1/imm32/rm32-is-first-inout
11111     3/imm32/r32-is-first-output
11112     0/imm32/no-imm32
11113     0/imm32/no-disp32
11114     0/imm32/output-is-write-only
11115     0x11/imm32/alloc-id:fake
11116     _Primitive-and-lit-with-reg/imm32/next
11117 _Primitive-and-lit-with-reg:  # (payload primitive)
11118     0x11/imm32/alloc-id:fake:payload
11119     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
11120     0x11/imm32/alloc-id:fake
11121     _string-and/imm32/name
11122     0x11/imm32/alloc-id:fake
11123     Single-lit-var/imm32/inouts
11124     0x11/imm32/alloc-id:fake
11125     Single-int-var-in-some-register/imm32/outputs
11126     0x11/imm32/alloc-id:fake
11127     _string_81_subop_and/imm32/subx-name
11128     3/imm32/rm32-is-first-output
11129     0/imm32/no-r32
11130     1/imm32/imm32-is-first-inout
11131     0/imm32/no-disp32
11132     0/imm32/output-is-write-only
11133     0x11/imm32/alloc-id:fake
11134     _Primitive-and-lit-with-mem/imm32/next
11135 _Primitive-and-lit-with-mem:  # (payload primitive)
11136     0x11/imm32/alloc-id:fake:payload
11137     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
11138     0x11/imm32/alloc-id:fake
11139     _string-and-with/imm32/name
11140     0x11/imm32/alloc-id:fake
11141     Int-var-and-literal/imm32/inouts
11142     0/imm32/no-outputs
11143     0/imm32/no-outputs
11144     0x11/imm32/alloc-id:fake
11145     _string_81_subop_and/imm32/subx-name
11146     1/imm32/rm32-is-first-inout
11147     0/imm32/no-r32
11148     2/imm32/imm32-is-first-inout
11149     0/imm32/no-disp32
11150     0/imm32/output-is-write-only
11151     0x11/imm32/alloc-id:fake
11152     _Primitive-or-with-eax/imm32/next
11153 # - or
11154 _Primitive-or-with-eax:  # (payload primitive)
11155     0x11/imm32/alloc-id:fake:payload
11156     # var/eax <- or lit => 0d/or-with-eax lit/imm32
11157     0x11/imm32/alloc-id:fake
11158     _string-or/imm32/name
11159     0x11/imm32/alloc-id:fake
11160     Single-lit-var/imm32/inouts
11161     0x11/imm32/alloc-id:fake
11162     Single-int-var-in-eax/imm32/outputs
11163     0x11/imm32/alloc-id:fake
11164     _string_0d_or_with_eax/imm32/subx-name
11165     0/imm32/no-rm32
11166     0/imm32/no-r32
11167     1/imm32/imm32-is-first-inout
11168     0/imm32/no-disp32
11169     0/imm32/output-is-write-only
11170     0x11/imm32/alloc-id:fake
11171     _Primitive-or-reg-with-reg/imm32/next
11172 _Primitive-or-reg-with-reg:  # (payload primitive)
11173     0x11/imm32/alloc-id:fake:payload
11174     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
11175     0x11/imm32/alloc-id:fake
11176     _string-or/imm32/name
11177     0x11/imm32/alloc-id:fake
11178     Single-int-var-in-some-register/imm32/inouts
11179     0x11/imm32/alloc-id:fake
11180     Single-int-var-in-some-register/imm32/outputs
11181     0x11/imm32/alloc-id:fake
11182     _string_09_or_with/imm32/subx-name
11183     3/imm32/rm32-is-first-output
11184     1/imm32/r32-is-first-inout
11185     0/imm32/no-imm32
11186     0/imm32/no-disp32
11187     0/imm32/output-is-write-only
11188     0x11/imm32/alloc-id:fake
11189     _Primitive-or-reg-with-mem/imm32/next
11190 _Primitive-or-reg-with-mem:  # (payload primitive)
11191     0x11/imm32/alloc-id:fake:payload
11192     # or-with var1 var2/reg => 09/or-with var1 var2/r32
11193     0x11/imm32/alloc-id:fake
11194     _string-or-with/imm32/name
11195     0x11/imm32/alloc-id:fake
11196     Two-args-int-stack-int-reg/imm32/inouts
11197     0/imm32/no-outputs
11198     0/imm32/no-outputs
11199     0x11/imm32/alloc-id:fake
11200     _string_09_or_with/imm32/subx-name
11201     1/imm32/rm32-is-first-inout
11202     2/imm32/r32-is-second-inout
11203     0/imm32/no-imm32
11204     0/imm32/no-disp32
11205     0/imm32/output-is-write-only
11206     0x11/imm32/alloc-id:fake
11207     _Primitive-or-mem-with-reg/imm32/next
11208 _Primitive-or-mem-with-reg:  # (payload primitive)
11209     0x11/imm32/alloc-id:fake:payload
11210     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
11211     0x11/imm32/alloc-id:fake
11212     _string-or/imm32/name
11213     0x11/imm32/alloc-id:fake
11214     Single-int-var-in-mem/imm32/inouts
11215     0x11/imm32/alloc-id:fake
11216     Single-int-var-in-some-register/imm32/outputs
11217     0x11/imm32/alloc-id:fake
11218     _string_0b_or/imm32/subx-name
11219     1/imm32/rm32-is-first-inout
11220     3/imm32/r32-is-first-output
11221     0/imm32/no-imm32
11222     0/imm32/no-disp32
11223     0/imm32/output-is-write-only
11224     0x11/imm32/alloc-id:fake
11225     _Primitive-or-lit-with-reg/imm32/next
11226 _Primitive-or-lit-with-reg:  # (payload primitive)
11227     0x11/imm32/alloc-id:fake:payload
11228     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
11229     0x11/imm32/alloc-id:fake
11230     _string-or/imm32/name
11231     0x11/imm32/alloc-id:fake
11232     Single-lit-var/imm32/inouts
11233     0x11/imm32/alloc-id:fake
11234     Single-int-var-in-some-register/imm32/outputs
11235     0x11/imm32/alloc-id:fake
11236     _string_81_subop_or/imm32/subx-name
11237     3/imm32/rm32-is-first-output
11238     0/imm32/no-r32
11239     1/imm32/imm32-is-first-inout
11240     0/imm32/no-disp32
11241     0/imm32/output-is-write-only
11242     0x11/imm32/alloc-id:fake
11243     _Primitive-or-lit-with-mem/imm32/next
11244 _Primitive-or-lit-with-mem:  # (payload primitive)
11245     0x11/imm32/alloc-id:fake:payload
11246     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
11247     0x11/imm32/alloc-id:fake
11248     _string-or-with/imm32/name
11249     0x11/imm32/alloc-id:fake
11250     Int-var-and-literal/imm32/inouts
11251     0/imm32/no-outputs
11252     0/imm32/no-outputs
11253     0x11/imm32/alloc-id:fake
11254     _string_81_subop_or/imm32/subx-name
11255     1/imm32/rm32-is-first-inout
11256     0/imm32/no-r32
11257     2/imm32/imm32-is-second-inout
11258     0/imm32/no-disp32
11259     0/imm32/output-is-write-only
11260     0x11/imm32/alloc-id:fake
11261     _Primitive-xor-with-eax/imm32/next
11262 # - xor
11263 _Primitive-xor-with-eax:  # (payload primitive)
11264     0x11/imm32/alloc-id:fake:payload
11265     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
11266     0x11/imm32/alloc-id:fake
11267     _string-xor/imm32/name
11268     0x11/imm32/alloc-id:fake
11269     Single-lit-var/imm32/inouts
11270     0x11/imm32/alloc-id:fake
11271     Single-int-var-in-eax/imm32/outputs
11272     0x11/imm32/alloc-id:fake
11273     _string_35_xor_with_eax/imm32/subx-name
11274     0/imm32/no-rm32
11275     0/imm32/no-r32
11276     1/imm32/imm32-is-first-inout
11277     0/imm32/no-disp32
11278     0/imm32/output-is-write-only
11279     0x11/imm32/alloc-id:fake
11280     _Primitive-xor-reg-with-reg/imm32/next
11281 _Primitive-xor-reg-with-reg:  # (payload primitive)
11282     0x11/imm32/alloc-id:fake:payload
11283     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
11284     0x11/imm32/alloc-id:fake
11285     _string-xor/imm32/name
11286     0x11/imm32/alloc-id:fake
11287     Single-int-var-in-some-register/imm32/inouts
11288     0x11/imm32/alloc-id:fake
11289     Single-int-var-in-some-register/imm32/outputs
11290     0x11/imm32/alloc-id:fake
11291     _string_31_xor_with/imm32/subx-name
11292     3/imm32/rm32-is-first-output
11293     1/imm32/r32-is-first-inout
11294     0/imm32/no-imm32
11295     0/imm32/no-disp32
11296     0/imm32/output-is-write-only
11297     0x11/imm32/alloc-id:fake
11298     _Primitive-xor-reg-with-mem/imm32/next
11299 _Primitive-xor-reg-with-mem:  # (payload primitive)
11300     0x11/imm32/alloc-id:fake:payload
11301     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
11302     0x11/imm32/alloc-id:fake
11303     _string-xor-with/imm32/name
11304     0x11/imm32/alloc-id:fake
11305     Two-args-int-stack-int-reg/imm32/inouts
11306     0/imm32/no-outputs
11307     0/imm32/no-outputs
11308     0x11/imm32/alloc-id:fake
11309     _string_31_xor_with/imm32/subx-name
11310     1/imm32/rm32-is-first-inout
11311     2/imm32/r32-is-second-inout
11312     0/imm32/no-imm32
11313     0/imm32/no-disp32
11314     0/imm32/output-is-write-only
11315     0x11/imm32/alloc-id:fake
11316     _Primitive-xor-mem-with-reg/imm32/next
11317 _Primitive-xor-mem-with-reg:  # (payload primitive)
11318     0x11/imm32/alloc-id:fake:payload
11319     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
11320     0x11/imm32/alloc-id:fake
11321     _string-xor/imm32/name
11322     0x11/imm32/alloc-id:fake
11323     Single-int-var-in-mem/imm32/inouts
11324     0x11/imm32/alloc-id:fake
11325     Single-int-var-in-some-register/imm32/outputs
11326     0x11/imm32/alloc-id:fake
11327     _string_33_xor/imm32/subx-name
11328     1/imm32/rm32-is-first-inout
11329     3/imm32/r32-is-first-output
11330     0/imm32/no-imm32
11331     0/imm32/no-disp32
11332     0/imm32/output-is-write-only
11333     0x11/imm32/alloc-id:fake
11334     _Primitive-xor-lit-with-reg/imm32/next
11335 _Primitive-xor-lit-with-reg:  # (payload primitive)
11336     0x11/imm32/alloc-id:fake:payload
11337     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
11338     0x11/imm32/alloc-id:fake
11339     _string-xor/imm32/name
11340     0x11/imm32/alloc-id:fake
11341     Single-lit-var/imm32/inouts
11342     0x11/imm32/alloc-id:fake
11343     Single-int-var-in-some-register/imm32/outputs
11344     0x11/imm32/alloc-id:fake
11345     _string_81_subop_xor/imm32/subx-name
11346     3/imm32/rm32-is-first-output
11347     0/imm32/no-r32
11348     1/imm32/imm32-is-first-inout
11349     0/imm32/no-disp32
11350     0/imm32/output-is-write-only
11351     0x11/imm32/alloc-id:fake
11352     _Primitive-xor-lit-with-mem/imm32/next
11353 _Primitive-xor-lit-with-mem:  # (payload primitive)
11354     0x11/imm32/alloc-id:fake:payload
11355     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
11356     0x11/imm32/alloc-id:fake
11357     _string-xor-with/imm32/name
11358     0x11/imm32/alloc-id:fake
11359     Int-var-and-literal/imm32/inouts
11360     0/imm32/no-outputs
11361     0/imm32/no-outputs
11362     0x11/imm32/alloc-id:fake
11363     _string_81_subop_xor/imm32/subx-name
11364     1/imm32/rm32-is-first-inout
11365     0/imm32/no-r32
11366     2/imm32/imm32-is-first-inout
11367     0/imm32/no-disp32
11368     0/imm32/output-is-write-only
11369     0x11/imm32/alloc-id:fake
11370     _Primitive-copy-to-eax/imm32/next
11371 # - copy
11372 _Primitive-copy-to-eax:  # (payload primitive)
11373     0x11/imm32/alloc-id:fake:payload
11374     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
11375     0x11/imm32/alloc-id:fake
11376     _string-copy/imm32/name
11377     0x11/imm32/alloc-id:fake
11378     Single-lit-var/imm32/inouts
11379     0x11/imm32/alloc-id:fake
11380     Single-int-var-in-eax/imm32/outputs
11381     0x11/imm32/alloc-id:fake
11382     _string_b8_copy_to_eax/imm32/subx-name
11383     0/imm32/no-rm32
11384     0/imm32/no-r32
11385     1/imm32/imm32-is-first-inout
11386     0/imm32/no-disp32
11387     1/imm32/output-is-write-only
11388     0x11/imm32/alloc-id:fake
11389     _Primitive-copy-to-ecx/imm32/next
11390 _Primitive-copy-to-ecx:  # (payload primitive)
11391     0x11/imm32/alloc-id:fake:payload
11392     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
11393     0x11/imm32/alloc-id:fake
11394     _string-copy/imm32/name
11395     0x11/imm32/alloc-id:fake
11396     Single-lit-var/imm32/inouts
11397     0x11/imm32/alloc-id:fake
11398     Single-int-var-in-ecx/imm32/outputs
11399     0x11/imm32/alloc-id:fake
11400     _string_b9_copy_to_ecx/imm32/subx-name
11401     0/imm32/no-rm32
11402     0/imm32/no-r32
11403     1/imm32/imm32-is-first-inout
11404     0/imm32/no-disp32
11405     1/imm32/output-is-write-only
11406     0x11/imm32/alloc-id:fake
11407     _Primitive-copy-to-edx/imm32/next
11408 _Primitive-copy-to-edx:  # (payload primitive)
11409     0x11/imm32/alloc-id:fake:payload
11410     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
11411     0x11/imm32/alloc-id:fake
11412     _string-copy/imm32/name
11413     0x11/imm32/alloc-id:fake
11414     Single-lit-var/imm32/inouts
11415     0x11/imm32/alloc-id:fake
11416     Single-int-var-in-edx/imm32/outputs
11417     0x11/imm32/alloc-id:fake
11418     _string_ba_copy_to_edx/imm32/subx-name
11419     0/imm32/no-rm32
11420     0/imm32/no-r32
11421     1/imm32/imm32-is-first-inout
11422     0/imm32/no-disp32
11423     1/imm32/output-is-write-only
11424     0x11/imm32/alloc-id:fake
11425     _Primitive-copy-to-ebx/imm32/next
11426 _Primitive-copy-to-ebx:  # (payload primitive)
11427     0x11/imm32/alloc-id:fake:payload
11428     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
11429     0x11/imm32/alloc-id:fake
11430     _string-copy/imm32/name
11431     0x11/imm32/alloc-id:fake
11432     Single-lit-var/imm32/inouts
11433     0x11/imm32/alloc-id:fake
11434     Single-int-var-in-ebx/imm32/outputs
11435     0x11/imm32/alloc-id:fake
11436     _string_bb_copy_to_ebx/imm32/subx-name
11437     0/imm32/no-rm32
11438     0/imm32/no-r32
11439     1/imm32/imm32-is-first-inout
11440     0/imm32/no-disp32
11441     1/imm32/output-is-write-only
11442     0x11/imm32/alloc-id:fake
11443     _Primitive-copy-to-esi/imm32/next
11444 _Primitive-copy-to-esi:  # (payload primitive)
11445     0x11/imm32/alloc-id:fake:payload
11446     # var/esi <- copy lit => be/copy-to-esi lit/imm32
11447     0x11/imm32/alloc-id:fake
11448     _string-copy/imm32/name
11449     0x11/imm32/alloc-id:fake
11450     Single-lit-var/imm32/inouts
11451     0x11/imm32/alloc-id:fake
11452     Single-int-var-in-esi/imm32/outputs
11453     0x11/imm32/alloc-id:fake
11454     _string_be_copy_to_esi/imm32/subx-name
11455     0/imm32/no-rm32
11456     0/imm32/no-r32
11457     1/imm32/imm32-is-first-inout
11458     0/imm32/no-disp32
11459     1/imm32/output-is-write-only
11460     0x11/imm32/alloc-id:fake
11461     _Primitive-copy-to-edi/imm32/next
11462 _Primitive-copy-to-edi:  # (payload primitive)
11463     0x11/imm32/alloc-id:fake:payload
11464     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
11465     0x11/imm32/alloc-id:fake
11466     _string-copy/imm32/name
11467     0x11/imm32/alloc-id:fake
11468     Single-lit-var/imm32/inouts
11469     0x11/imm32/alloc-id:fake
11470     Single-int-var-in-edi/imm32/outputs
11471     0x11/imm32/alloc-id:fake
11472     _string_bf_copy_to_edi/imm32/subx-name
11473     0/imm32/no-rm32
11474     0/imm32/no-r32
11475     1/imm32/imm32-is-first-inout
11476     0/imm32/no-disp32
11477     1/imm32/output-is-write-only
11478     0x11/imm32/alloc-id:fake
11479     _Primitive-copy-reg-to-reg/imm32/next
11480 _Primitive-copy-reg-to-reg:  # (payload primitive)
11481     0x11/imm32/alloc-id:fake:payload
11482     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
11483     0x11/imm32/alloc-id:fake
11484     _string-copy/imm32/name
11485     0x11/imm32/alloc-id:fake
11486     Single-int-var-in-some-register/imm32/inouts
11487     0x11/imm32/alloc-id:fake
11488     Single-int-var-in-some-register/imm32/outputs
11489     0x11/imm32/alloc-id:fake
11490     _string_89_<-/imm32/subx-name
11491     3/imm32/rm32-is-first-output
11492     1/imm32/r32-is-first-inout
11493     0/imm32/no-imm32
11494     0/imm32/no-disp32
11495     1/imm32/output-is-write-only
11496     0x11/imm32/alloc-id:fake
11497     _Primitive-copy-reg-to-mem/imm32/next
11498 _Primitive-copy-reg-to-mem:  # (payload primitive)
11499     0x11/imm32/alloc-id:fake:payload
11500     # copy-to var1 var2/reg => 89/<- var1 var2/r32
11501     0x11/imm32/alloc-id:fake
11502     _string-copy-to/imm32/name
11503     0x11/imm32/alloc-id:fake
11504     Two-args-int-stack-int-reg/imm32/inouts
11505     0/imm32/no-outputs
11506     0/imm32/no-outputs
11507     0x11/imm32/alloc-id:fake
11508     _string_89_<-/imm32/subx-name
11509     1/imm32/rm32-is-first-inout
11510     2/imm32/r32-is-second-inout
11511     0/imm32/no-imm32
11512     0/imm32/no-disp32
11513     1/imm32/output-is-write-only
11514     0x11/imm32/alloc-id:fake
11515     _Primitive-copy-mem-to-reg/imm32/next
11516 _Primitive-copy-mem-to-reg:  # (payload primitive)
11517     0x11/imm32/alloc-id:fake:payload
11518     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
11519     0x11/imm32/alloc-id:fake
11520     _string-copy/imm32/name
11521     0x11/imm32/alloc-id:fake
11522     Single-int-var-in-mem/imm32/inouts
11523     0x11/imm32/alloc-id:fake
11524     Single-int-var-in-some-register/imm32/outputs
11525     0x11/imm32/alloc-id:fake
11526     _string_8b_->/imm32/subx-name
11527     1/imm32/rm32-is-first-inout
11528     3/imm32/r32-is-first-output
11529     0/imm32/no-imm32
11530     0/imm32/no-disp32
11531     1/imm32/output-is-write-only
11532     0x11/imm32/alloc-id:fake
11533     _Primitive-copy-lit-to-reg/imm32/next
11534 _Primitive-copy-lit-to-reg:  # (payload primitive)
11535     0x11/imm32/alloc-id:fake:payload
11536     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
11537     0x11/imm32/alloc-id:fake
11538     _string-copy/imm32/name
11539     0x11/imm32/alloc-id:fake
11540     Single-lit-var/imm32/inouts
11541     0x11/imm32/alloc-id:fake
11542     Single-int-var-in-some-register/imm32/outputs
11543     0x11/imm32/alloc-id:fake
11544     _string_c7_subop_copy/imm32/subx-name
11545     3/imm32/rm32-is-first-output
11546     0/imm32/no-r32
11547     1/imm32/imm32-is-first-inout
11548     0/imm32/no-disp32
11549     1/imm32/output-is-write-only
11550     0x11/imm32/alloc-id:fake
11551     _Primitive-copy-lit-to-mem/imm32/next
11552 _Primitive-copy-lit-to-mem:  # (payload primitive)
11553     0x11/imm32/alloc-id:fake:payload
11554     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
11555     0x11/imm32/alloc-id:fake
11556     _string-copy-to/imm32/name
11557     0x11/imm32/alloc-id:fake
11558     Int-var-and-literal/imm32/inouts
11559     0/imm32/no-outputs
11560     0/imm32/no-outputs
11561     0x11/imm32/alloc-id:fake
11562     _string_c7_subop_copy/imm32/subx-name
11563     1/imm32/rm32-is-first-inout
11564     0/imm32/no-r32
11565     2/imm32/imm32-is-first-inout
11566     0/imm32/no-disp32
11567     1/imm32/output-is-write-only
11568     0x11/imm32/alloc-id:fake
11569     _Primitive-copy-byte-from-reg/imm32/next
11570 # - copy byte
11571 _Primitive-copy-byte-from-reg:
11572     0x11/imm32/alloc-id:fake:payload
11573     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
11574     0x11/imm32/alloc-id:fake
11575     _string-copy-byte/imm32/name
11576     0x11/imm32/alloc-id:fake
11577     Single-byte-var-in-some-register/imm32/inouts
11578     0x11/imm32/alloc-id:fake
11579     Single-byte-var-in-some-register/imm32/outputs
11580     0x11/imm32/alloc-id:fake
11581     _string_8a_copy_byte/imm32/subx-name
11582     1/imm32/rm32-is-first-inout
11583     3/imm32/r32-is-first-output
11584     0/imm32/no-imm32
11585     0/imm32/no-disp32
11586     1/imm32/output-is-write-only
11587     0x11/imm32/alloc-id:fake
11588     _Primitive-copy-byte-from-mem/imm32/next
11589 _Primitive-copy-byte-from-mem:
11590     0x11/imm32/alloc-id:fake:payload
11591     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
11592     0x11/imm32/alloc-id:fake
11593     _string-copy-byte/imm32/name
11594     0x11/imm32/alloc-id:fake
11595     Single-byte-var-in-mem/imm32/inouts
11596     0x11/imm32/alloc-id:fake
11597     Single-byte-var-in-some-register/imm32/outputs
11598     0x11/imm32/alloc-id:fake
11599     _string_8a_copy_byte/imm32/subx-name
11600     1/imm32/rm32-is-first-inout
11601     3/imm32/r32-is-first-output
11602     0/imm32/no-imm32
11603     0/imm32/no-disp32
11604     1/imm32/output-is-write-only
11605     0x11/imm32/alloc-id:fake
11606     _Primitive-copy-byte-to-mem/imm32/next
11607 _Primitive-copy-byte-to-mem:
11608     0x11/imm32/alloc-id:fake:payload
11609     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
11610     0x11/imm32/alloc-id:fake
11611     _string-copy-byte-to/imm32/name
11612     0x11/imm32/alloc-id:fake
11613     Two-args-byte-stack-byte-reg/imm32/inouts
11614     0/imm32/no-outputs
11615     0/imm32/no-outputs
11616     0x11/imm32/alloc-id:fake
11617     _string_88_copy_byte/imm32/subx-name
11618     1/imm32/rm32-is-first-inout
11619     2/imm32/r32-is-second-inout
11620     0/imm32/no-imm32
11621     0/imm32/no-disp32
11622     0/imm32/output-is-write-only
11623     0x11/imm32/alloc-id:fake
11624     _Primitive-address/imm32/next
11625 # - address
11626 _Primitive-address:  # (payload primitive)
11627     0x11/imm32/alloc-id:fake:payload
11628     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
11629     0x11/imm32/alloc-id:fake
11630     _string-address/imm32/name
11631     0x11/imm32/alloc-id:fake
11632     Single-int-var-in-mem/imm32/inouts
11633     0x11/imm32/alloc-id:fake
11634     Single-addr-var-in-some-register/imm32/outputs
11635     0x11/imm32/alloc-id:fake
11636     _string_8d_copy_address/imm32/subx-name
11637     1/imm32/rm32-is-first-inout
11638     3/imm32/r32-is-first-output
11639     0/imm32/no-imm32
11640     0/imm32/no-disp32
11641     1/imm32/output-is-write-only
11642     0x11/imm32/alloc-id:fake
11643     _Primitive-compare-mem-with-reg/imm32/next
11644 # - compare
11645 _Primitive-compare-mem-with-reg:  # (payload primitive)
11646     0x11/imm32/alloc-id:fake:payload
11647     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
11648     0x11/imm32/alloc-id:fake
11649     _string-compare/imm32/name
11650     0x11/imm32/alloc-id:fake
11651     Two-args-int-stack-int-reg/imm32/inouts
11652     0/imm32/no-outputs
11653     0/imm32/no-outputs
11654     0x11/imm32/alloc-id:fake
11655     _string_39_compare->/imm32/subx-name
11656     1/imm32/rm32-is-first-inout
11657     2/imm32/r32-is-second-inout
11658     0/imm32/no-imm32
11659     0/imm32/no-disp32
11660     0/imm32/output-is-write-only
11661     0x11/imm32/alloc-id:fake
11662     _Primitive-compare-reg-with-mem/imm32/next
11663 _Primitive-compare-reg-with-mem:  # (payload primitive)
11664     0x11/imm32/alloc-id:fake:payload
11665     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
11666     0x11/imm32/alloc-id:fake
11667     _string-compare/imm32/name
11668     0x11/imm32/alloc-id:fake
11669     Two-args-int-reg-int-stack/imm32/inouts
11670     0/imm32/no-outputs
11671     0/imm32/no-outputs
11672     0x11/imm32/alloc-id:fake
11673     _string_3b_compare<-/imm32/subx-name
11674     2/imm32/rm32-is-second-inout
11675     1/imm32/r32-is-first-inout
11676     0/imm32/no-imm32
11677     0/imm32/no-disp32
11678     0/imm32/output-is-write-only
11679     0x11/imm32/alloc-id:fake
11680     _Primitive-compare-eax-with-literal/imm32/next
11681 _Primitive-compare-eax-with-literal:  # (payload primitive)
11682     0x11/imm32/alloc-id:fake:payload
11683     # compare var1/eax n => 3d/compare-eax-with n/imm32
11684     0x11/imm32/alloc-id:fake
11685     _string-compare/imm32/name
11686     0x11/imm32/alloc-id:fake
11687     Two-args-int-eax-int-literal/imm32/inouts
11688     0/imm32/no-outputs
11689     0/imm32/no-outputs
11690     0x11/imm32/alloc-id:fake
11691     _string_3d_compare_eax_with/imm32/subx-name
11692     0/imm32/no-rm32
11693     0/imm32/no-r32
11694     2/imm32/imm32-is-second-inout
11695     0/imm32/no-disp32
11696     0/imm32/output-is-write-only
11697     0x11/imm32/alloc-id:fake
11698     _Primitive-compare-reg-with-literal/imm32/next
11699 _Primitive-compare-reg-with-literal:  # (payload primitive)
11700     0x11/imm32/alloc-id:fake:payload
11701     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
11702     0x11/imm32/alloc-id:fake
11703     _string-compare/imm32/name
11704     0x11/imm32/alloc-id:fake
11705     Int-var-in-register-and-literal/imm32/inouts
11706     0/imm32/no-outputs
11707     0/imm32/no-outputs
11708     0x11/imm32/alloc-id:fake
11709     _string_81_subop_compare/imm32/subx-name
11710     1/imm32/rm32-is-first-inout
11711     0/imm32/no-r32
11712     2/imm32/imm32-is-second-inout
11713     0/imm32/no-disp32
11714     0/imm32/output-is-write-only
11715     0x11/imm32/alloc-id:fake
11716     _Primitive-compare-mem-with-literal/imm32/next
11717 _Primitive-compare-mem-with-literal:  # (payload primitive)
11718     0x11/imm32/alloc-id:fake:payload
11719     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
11720     0x11/imm32/alloc-id:fake
11721     _string-compare/imm32/name
11722     0x11/imm32/alloc-id:fake
11723     Int-var-and-literal/imm32/inouts
11724     0/imm32/no-outputs
11725     0/imm32/no-outputs
11726     0x11/imm32/alloc-id:fake
11727     _string_81_subop_compare/imm32/subx-name
11728     1/imm32/rm32-is-first-inout
11729     0/imm32/no-r32
11730     2/imm32/imm32-is-second-inout
11731     0/imm32/no-disp32
11732     0/imm32/output-is-write-only
11733     0x11/imm32/alloc-id:fake
11734     _Primitive-multiply-reg-by-mem/imm32/next
11735 # - multiply
11736 _Primitive-multiply-reg-by-mem:  # (payload primitive)
11737     0x11/imm32/alloc-id:fake:payload
11738     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
11739     0x11/imm32/alloc-id:fake
11740     _string-multiply/imm32/name
11741     0x11/imm32/alloc-id:fake
11742     Single-int-var-in-mem/imm32/inouts
11743     0x11/imm32/alloc-id:fake
11744     Single-int-var-in-some-register/imm32/outputs
11745     0x11/imm32/alloc-id:fake
11746     _string_0f_af_multiply/imm32/subx-name
11747     1/imm32/rm32-is-first-inout
11748     3/imm32/r32-is-first-output
11749     0/imm32/no-imm32
11750     0/imm32/no-disp32
11751     0/imm32/output-is-write-only
11752     0x11/imm32/alloc-id:fake
11753     _Primitive-break-if-addr</imm32/next
11754 # - branches
11755 _Primitive-break-if-addr<:  # (payload primitive)
11756     0x11/imm32/alloc-id:fake:payload
11757     0x11/imm32/alloc-id:fake
11758     _string-break-if-addr</imm32/name
11759     0/imm32/no-inouts
11760     0/imm32/no-inouts
11761     0/imm32/no-outputs
11762     0/imm32/no-outputs
11763     0x11/imm32/alloc-id:fake
11764     _string_0f_82_jump_break/imm32/subx-name
11765     0/imm32/no-rm32
11766     0/imm32/no-r32
11767     0/imm32/no-imm32
11768     0/imm32/no-disp32
11769     0/imm32/no-output
11770     0x11/imm32/alloc-id:fake
11771     _Primitive-break-if-addr>=/imm32/next
11772 _Primitive-break-if-addr>=:  # (payload primitive)
11773     0x11/imm32/alloc-id:fake:payload
11774     0x11/imm32/alloc-id:fake
11775     _string-break-if-addr>=/imm32/name
11776     0/imm32/no-inouts
11777     0/imm32/no-inouts
11778     0/imm32/no-outputs
11779     0/imm32/no-outputs
11780     0x11/imm32/alloc-id:fake
11781     _string_0f_83_jump_break/imm32/subx-name
11782     0/imm32/no-rm32
11783     0/imm32/no-r32
11784     0/imm32/no-imm32
11785     0/imm32/no-disp32
11786     0/imm32/no-output
11787     0x11/imm32/alloc-id:fake
11788     _Primitive-break-if-=/imm32/next
11789 _Primitive-break-if-=:  # (payload primitive)
11790     0x11/imm32/alloc-id:fake:payload
11791     0x11/imm32/alloc-id:fake
11792     _string-break-if-=/imm32/name
11793     0/imm32/no-inouts
11794     0/imm32/no-inouts
11795     0/imm32/no-outputs
11796     0/imm32/no-outputs
11797     0x11/imm32/alloc-id:fake
11798     _string_0f_84_jump_break/imm32/subx-name
11799     0/imm32/no-rm32
11800     0/imm32/no-r32
11801     0/imm32/no-imm32
11802     0/imm32/no-disp32
11803     0/imm32/no-output
11804     0x11/imm32/alloc-id:fake
11805     _Primitive-break-if-!=/imm32/next
11806 _Primitive-break-if-!=:  # (payload primitive)
11807     0x11/imm32/alloc-id:fake:payload
11808     0x11/imm32/alloc-id:fake
11809     _string-break-if-!=/imm32/name
11810     0/imm32/no-inouts
11811     0/imm32/no-inouts
11812     0/imm32/no-outputs
11813     0/imm32/no-outputs
11814     0x11/imm32/alloc-id:fake
11815     _string_0f_85_jump_break/imm32/subx-name
11816     0/imm32/no-rm32
11817     0/imm32/no-r32
11818     0/imm32/no-imm32
11819     0/imm32/no-disp32
11820     0/imm32/no-output
11821     0x11/imm32/alloc-id:fake
11822     _Primitive-break-if-addr<=/imm32/next
11823 _Primitive-break-if-addr<=:  # (payload primitive)
11824     0x11/imm32/alloc-id:fake:payload
11825     0x11/imm32/alloc-id:fake
11826     _string-break-if-addr<=/imm32/name
11827     0/imm32/no-inouts
11828     0/imm32/no-inouts
11829     0/imm32/no-outputs
11830     0/imm32/no-outputs
11831     0x11/imm32/alloc-id:fake
11832     _string_0f_86_jump_break/imm32/subx-name
11833     0/imm32/no-rm32
11834     0/imm32/no-r32
11835     0/imm32/no-imm32
11836     0/imm32/no-disp32
11837     0/imm32/no-output
11838     0x11/imm32/alloc-id:fake
11839     _Primitive-break-if-addr>/imm32/next
11840 _Primitive-break-if-addr>:  # (payload primitive)
11841     0x11/imm32/alloc-id:fake:payload
11842     0x11/imm32/alloc-id:fake
11843     _string-break-if-addr>/imm32/name
11844     0/imm32/no-inouts
11845     0/imm32/no-inouts
11846     0/imm32/no-outputs
11847     0/imm32/no-outputs
11848     0x11/imm32/alloc-id:fake
11849     _string_0f_87_jump_break/imm32/subx-name
11850     0/imm32/no-rm32
11851     0/imm32/no-r32
11852     0/imm32/no-imm32
11853     0/imm32/no-disp32
11854     0/imm32/no-output
11855     0x11/imm32/alloc-id:fake
11856     _Primitive-break-if-</imm32/next
11857 _Primitive-break-if-<:  # (payload primitive)
11858     0x11/imm32/alloc-id:fake:payload
11859     0x11/imm32/alloc-id:fake
11860     _string-break-if-</imm32/name
11861     0/imm32/no-inouts
11862     0/imm32/no-inouts
11863     0/imm32/no-outputs
11864     0/imm32/no-outputs
11865     0x11/imm32/alloc-id:fake
11866     _string_0f_8c_jump_break/imm32/subx-name
11867     0/imm32/no-rm32
11868     0/imm32/no-r32
11869     0/imm32/no-imm32
11870     0/imm32/no-disp32
11871     0/imm32/no-output
11872     0x11/imm32/alloc-id:fake
11873     _Primitive-break-if->=/imm32/next
11874 _Primitive-break-if->=:  # (payload primitive)
11875     0x11/imm32/alloc-id:fake:payload
11876     0x11/imm32/alloc-id:fake
11877     _string-break-if->=/imm32/name
11878     0/imm32/no-inouts
11879     0/imm32/no-inouts
11880     0/imm32/no-outputs
11881     0/imm32/no-outputs
11882     0x11/imm32/alloc-id:fake
11883     _string_0f_8d_jump_break/imm32/subx-name
11884     0/imm32/no-rm32
11885     0/imm32/no-r32
11886     0/imm32/no-imm32
11887     0/imm32/no-disp32
11888     0/imm32/no-output
11889     0x11/imm32/alloc-id:fake
11890     _Primitive-break-if-<=/imm32/next
11891 _Primitive-break-if-<=:  # (payload primitive)
11892     0x11/imm32/alloc-id:fake:payload
11893     0x11/imm32/alloc-id:fake
11894     _string-break-if-<=/imm32/name
11895     0/imm32/no-inouts
11896     0/imm32/no-inouts
11897     0/imm32/no-outputs
11898     0/imm32/no-outputs
11899     0x11/imm32/alloc-id:fake
11900     _string_0f_8e_jump_break/imm32/subx-name
11901     0/imm32/no-rm32
11902     0/imm32/no-r32
11903     0/imm32/no-imm32
11904     0/imm32/no-disp32
11905     0/imm32/no-output
11906     0x11/imm32/alloc-id:fake
11907     _Primitive-break-if->/imm32/next
11908 _Primitive-break-if->:  # (payload primitive)
11909     0x11/imm32/alloc-id:fake:payload
11910     0x11/imm32/alloc-id:fake
11911     _string-break-if->/imm32/name
11912     0/imm32/no-inouts
11913     0/imm32/no-inouts
11914     0/imm32/no-outputs
11915     0/imm32/no-outputs
11916     0x11/imm32/alloc-id:fake
11917     _string_0f_8f_jump_break/imm32/subx-name
11918     0/imm32/no-rm32
11919     0/imm32/no-r32
11920     0/imm32/no-imm32
11921     0/imm32/no-disp32
11922     0/imm32/no-output
11923     0x11/imm32/alloc-id:fake
11924     _Primitive-break/imm32/next
11925 _Primitive-break:  # (payload primitive)
11926     0x11/imm32/alloc-id:fake:payload
11927     0x11/imm32/alloc-id:fake
11928     _string-break/imm32/name
11929     0/imm32/no-inouts
11930     0/imm32/no-inouts
11931     0/imm32/no-outputs
11932     0/imm32/no-outputs
11933     0x11/imm32/alloc-id:fake
11934     _string_e9_jump_break/imm32/subx-name
11935     0/imm32/no-rm32
11936     0/imm32/no-r32
11937     0/imm32/no-imm32
11938     0/imm32/no-disp32
11939     0/imm32/no-output
11940     0x11/imm32/alloc-id:fake
11941     _Primitive-loop-if-addr</imm32/next
11942 _Primitive-loop-if-addr<:  # (payload primitive)
11943     0x11/imm32/alloc-id:fake:payload
11944     0x11/imm32/alloc-id:fake
11945     _string-loop-if-addr</imm32/name
11946     0/imm32/no-inouts
11947     0/imm32/no-inouts
11948     0/imm32/no-outputs
11949     0/imm32/no-outputs
11950     0x11/imm32/alloc-id:fake
11951     _string_0f_82_jump_loop/imm32/subx-name
11952     0/imm32/no-rm32
11953     0/imm32/no-r32
11954     0/imm32/no-imm32
11955     0/imm32/no-disp32
11956     0/imm32/no-output
11957     0x11/imm32/alloc-id:fake
11958     _Primitive-loop-if-addr>=/imm32/next
11959 _Primitive-loop-if-addr>=:  # (payload primitive)
11960     0x11/imm32/alloc-id:fake:payload
11961     0x11/imm32/alloc-id:fake
11962     _string-loop-if-addr>=/imm32/name
11963     0/imm32/no-inouts
11964     0/imm32/no-inouts
11965     0/imm32/no-outputs
11966     0/imm32/no-outputs
11967     0x11/imm32/alloc-id:fake
11968     _string_0f_83_jump_loop/imm32/subx-name
11969     0/imm32/no-rm32
11970     0/imm32/no-r32
11971     0/imm32/no-imm32
11972     0/imm32/no-disp32
11973     0/imm32/no-output
11974     0x11/imm32/alloc-id:fake
11975     _Primitive-loop-if-=/imm32/next
11976 _Primitive-loop-if-=:  # (payload primitive)
11977     0x11/imm32/alloc-id:fake:payload
11978     0x11/imm32/alloc-id:fake
11979     _string-loop-if-=/imm32/name
11980     0/imm32/no-inouts
11981     0/imm32/no-inouts
11982     0/imm32/no-outputs
11983     0/imm32/no-outputs
11984     0x11/imm32/alloc-id:fake
11985     _string_0f_84_jump_loop/imm32/subx-name
11986     0/imm32/no-rm32
11987     0/imm32/no-r32
11988     0/imm32/no-imm32
11989     0/imm32/no-disp32
11990     0/imm32/no-output
11991     0x11/imm32/alloc-id:fake
11992     _Primitive-loop-if-!=/imm32/next
11993 _Primitive-loop-if-!=:  # (payload primitive)
11994     0x11/imm32/alloc-id:fake:payload
11995     0x11/imm32/alloc-id:fake
11996     _string-loop-if-!=/imm32/name
11997     0/imm32/no-inouts
11998     0/imm32/no-inouts
11999     0/imm32/no-outputs
12000     0/imm32/no-outputs
12001     0x11/imm32/alloc-id:fake
12002     _string_0f_85_jump_loop/imm32/subx-name
12003     0/imm32/no-rm32
12004     0/imm32/no-r32
12005     0/imm32/no-imm32
12006     0/imm32/no-disp32
12007     0/imm32/no-output
12008     0x11/imm32/alloc-id:fake
12009     _Primitive-loop-if-addr<=/imm32/next
12010 _Primitive-loop-if-addr<=:  # (payload primitive)
12011     0x11/imm32/alloc-id:fake:payload
12012     0x11/imm32/alloc-id:fake
12013     _string-loop-if-addr<=/imm32/name
12014     0/imm32/no-inouts
12015     0/imm32/no-inouts
12016     0/imm32/no-outputs
12017     0/imm32/no-outputs
12018     0x11/imm32/alloc-id:fake
12019     _string_0f_86_jump_loop/imm32/subx-name
12020     0/imm32/no-rm32
12021     0/imm32/no-r32
12022     0/imm32/no-imm32
12023     0/imm32/no-disp32
12024     0/imm32/no-output
12025     0x11/imm32/alloc-id:fake
12026     _Primitive-loop-if-addr>/imm32/next
12027 _Primitive-loop-if-addr>:  # (payload primitive)
12028     0x11/imm32/alloc-id:fake:payload
12029     0x11/imm32/alloc-id:fake
12030     _string-loop-if-addr>/imm32/name
12031     0/imm32/no-inouts
12032     0/imm32/no-inouts
12033     0/imm32/no-outputs
12034     0/imm32/no-outputs
12035     0x11/imm32/alloc-id:fake
12036     _string_0f_87_jump_loop/imm32/subx-name
12037     0/imm32/no-rm32
12038     0/imm32/no-r32
12039     0/imm32/no-imm32
12040     0/imm32/no-disp32
12041     0/imm32/no-output
12042     0x11/imm32/alloc-id:fake
12043     _Primitive-loop-if-</imm32/next
12044 _Primitive-loop-if-<:  # (payload primitive)
12045     0x11/imm32/alloc-id:fake:payload
12046     0x11/imm32/alloc-id:fake
12047     _string-loop-if-</imm32/name
12048     0/imm32/no-inouts
12049     0/imm32/no-inouts
12050     0/imm32/no-outputs
12051     0/imm32/no-outputs
12052     0x11/imm32/alloc-id:fake
12053     _string_0f_8c_jump_loop/imm32/subx-name
12054     0/imm32/no-rm32
12055     0/imm32/no-r32
12056     0/imm32/no-imm32
12057     0/imm32/no-disp32
12058     0/imm32/no-output
12059     0x11/imm32/alloc-id:fake
12060     _Primitive-loop-if->=/imm32/next
12061 _Primitive-loop-if->=:  # (payload primitive)
12062     0x11/imm32/alloc-id:fake:payload
12063     0x11/imm32/alloc-id:fake
12064     _string-loop-if->=/imm32/name
12065     0/imm32/no-inouts
12066     0/imm32/no-inouts
12067     0/imm32/no-outputs
12068     0/imm32/no-outputs
12069     0x11/imm32/alloc-id:fake
12070     _string_0f_8d_jump_loop/imm32/subx-name
12071     0/imm32/no-rm32
12072     0/imm32/no-r32
12073     0/imm32/no-imm32
12074     0/imm32/no-disp32
12075     0/imm32/no-output
12076     0x11/imm32/alloc-id:fake
12077     _Primitive-loop-if-<=/imm32/next
12078 _Primitive-loop-if-<=:  # (payload primitive)
12079     0x11/imm32/alloc-id:fake:payload
12080     0x11/imm32/alloc-id:fake
12081     _string-loop-if-<=/imm32/name
12082     0/imm32/no-inouts
12083     0/imm32/no-inouts
12084     0/imm32/no-outputs
12085     0/imm32/no-outputs
12086     0x11/imm32/alloc-id:fake
12087     _string_0f_8e_jump_loop/imm32/subx-name
12088     0/imm32/no-rm32
12089     0/imm32/no-r32
12090     0/imm32/no-imm32
12091     0/imm32/no-disp32
12092     0/imm32/no-output
12093     0x11/imm32/alloc-id:fake
12094     _Primitive-loop-if->/imm32/next
12095 _Primitive-loop-if->:  # (payload primitive)
12096     0x11/imm32/alloc-id:fake:payload
12097     0x11/imm32/alloc-id:fake
12098     _string-loop-if->/imm32/name
12099     0/imm32/no-inouts
12100     0/imm32/no-inouts
12101     0/imm32/no-outputs
12102     0/imm32/no-outputs
12103     0x11/imm32/alloc-id:fake
12104     _string_0f_8f_jump_loop/imm32/subx-name
12105     0/imm32/no-rm32
12106     0/imm32/no-r32
12107     0/imm32/no-imm32
12108     0/imm32/no-disp32
12109     0/imm32/no-output
12110     0x11/imm32/alloc-id:fake
12111     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
12112 _Primitive-loop:  # (payload primitive)
12113     0x11/imm32/alloc-id:fake:payload
12114     0x11/imm32/alloc-id:fake
12115     _string-loop/imm32/name
12116     0/imm32/no-inouts
12117     0/imm32/no-inouts
12118     0/imm32/no-outputs
12119     0/imm32/no-outputs
12120     0x11/imm32/alloc-id:fake
12121     _string_e9_jump_loop/imm32/subx-name
12122     0/imm32/no-rm32
12123     0/imm32/no-r32
12124     0/imm32/no-imm32
12125     0/imm32/no-disp32
12126     0/imm32/no-output
12127     0x11/imm32/alloc-id:fake
12128     _Primitive-break-if-addr<-named/imm32/next
12129 # - branches to named blocks
12130 _Primitive-break-if-addr<-named:  # (payload primitive)
12131     0x11/imm32/alloc-id:fake:payload
12132     0x11/imm32/alloc-id:fake
12133     _string-break-if-addr</imm32/name
12134     0x11/imm32/alloc-id:fake
12135     Single-lit-var/imm32/inouts
12136     0/imm32/no-outputs
12137     0/imm32/no-outputs
12138     0x11/imm32/alloc-id:fake
12139     _string_0f_82_jump_label/imm32/subx-name
12140     0/imm32/no-rm32
12141     0/imm32/no-r32
12142     0/imm32/no-imm32
12143     1/imm32/disp32-is-first-inout
12144     0/imm32/no-output
12145     0x11/imm32/alloc-id:fake
12146     _Primitive-break-if-addr>=-named/imm32/next
12147 _Primitive-break-if-addr>=-named:  # (payload primitive)
12148     0x11/imm32/alloc-id:fake:payload
12149     0x11/imm32/alloc-id:fake
12150     _string-break-if-addr>=/imm32/name
12151     0x11/imm32/alloc-id:fake
12152     Single-lit-var/imm32/inouts
12153     0/imm32/no-outputs
12154     0/imm32/no-outputs
12155     0x11/imm32/alloc-id:fake
12156     _string_0f_83_jump_label/imm32/subx-name
12157     0/imm32/no-rm32
12158     0/imm32/no-r32
12159     0/imm32/no-imm32
12160     1/imm32/disp32-is-first-inout
12161     0/imm32/no-output
12162     0x11/imm32/alloc-id:fake
12163     _Primitive-break-if-=-named/imm32/next
12164 _Primitive-break-if-=-named:  # (payload primitive)
12165     0x11/imm32/alloc-id:fake:payload
12166     0x11/imm32/alloc-id:fake
12167     _string-break-if-=/imm32/name
12168     0x11/imm32/alloc-id:fake
12169     Single-lit-var/imm32/inouts
12170     0/imm32/no-outputs
12171     0/imm32/no-outputs
12172     0x11/imm32/alloc-id:fake
12173     _string_0f_84_jump_label/imm32/subx-name
12174     0/imm32/no-rm32
12175     0/imm32/no-r32
12176     0/imm32/no-imm32
12177     1/imm32/disp32-is-first-inout
12178     0/imm32/no-output
12179     0x11/imm32/alloc-id:fake
12180     _Primitive-break-if-!=-named/imm32/next
12181 _Primitive-break-if-!=-named:  # (payload primitive)
12182     0x11/imm32/alloc-id:fake:payload
12183     0x11/imm32/alloc-id:fake
12184     _string-break-if-!=/imm32/name
12185     0x11/imm32/alloc-id:fake
12186     Single-lit-var/imm32/inouts
12187     0/imm32/no-outputs
12188     0/imm32/no-outputs
12189     0x11/imm32/alloc-id:fake
12190     _string_0f_85_jump_label/imm32/subx-name
12191     0/imm32/no-rm32
12192     0/imm32/no-r32
12193     0/imm32/no-imm32
12194     1/imm32/disp32-is-first-inout
12195     0/imm32/no-output
12196     0x11/imm32/alloc-id:fake
12197     _Primitive-break-if-addr<=-named/imm32/next
12198 _Primitive-break-if-addr<=-named:  # (payload primitive)
12199     0x11/imm32/alloc-id:fake:payload
12200     0x11/imm32/alloc-id:fake
12201     _string-break-if-addr<=/imm32/name
12202     0x11/imm32/alloc-id:fake
12203     Single-lit-var/imm32/inouts
12204     0/imm32/no-outputs
12205     0/imm32/no-outputs
12206     0x11/imm32/alloc-id:fake
12207     _string_0f_86_jump_label/imm32/subx-name
12208     0/imm32/no-rm32
12209     0/imm32/no-r32
12210     0/imm32/no-imm32
12211     1/imm32/disp32-is-first-inout
12212     0/imm32/no-output
12213     0x11/imm32/alloc-id:fake
12214     _Primitive-break-if-addr>-named/imm32/next
12215 _Primitive-break-if-addr>-named:  # (payload primitive)
12216     0x11/imm32/alloc-id:fake:payload
12217     0x11/imm32/alloc-id:fake
12218     _string-break-if-addr>/imm32/name
12219     0x11/imm32/alloc-id:fake
12220     Single-lit-var/imm32/inouts
12221     0/imm32/no-outputs
12222     0/imm32/no-outputs
12223     0x11/imm32/alloc-id:fake
12224     _string_0f_87_jump_label/imm32/subx-name
12225     0/imm32/no-rm32
12226     0/imm32/no-r32
12227     0/imm32/no-imm32
12228     1/imm32/disp32-is-first-inout
12229     0/imm32/no-output
12230     0x11/imm32/alloc-id:fake
12231     _Primitive-break-if-<-named/imm32/next
12232 _Primitive-break-if-<-named:  # (payload primitive)
12233     0x11/imm32/alloc-id:fake:payload
12234     0x11/imm32/alloc-id:fake
12235     _string-break-if-</imm32/name
12236     0x11/imm32/alloc-id:fake
12237     Single-lit-var/imm32/inouts
12238     0/imm32/no-outputs
12239     0/imm32/no-outputs
12240     0x11/imm32/alloc-id:fake
12241     _string_0f_8c_jump_label/imm32/subx-name
12242     0/imm32/no-rm32
12243     0/imm32/no-r32
12244     0/imm32/no-imm32
12245     1/imm32/disp32-is-first-inout
12246     0/imm32/no-output
12247     0x11/imm32/alloc-id:fake
12248     _Primitive-break-if->=-named/imm32/next
12249 _Primitive-break-if->=-named:  # (payload primitive)
12250     0x11/imm32/alloc-id:fake:payload
12251     0x11/imm32/alloc-id:fake
12252     _string-break-if->=/imm32/name
12253     0x11/imm32/alloc-id:fake
12254     Single-lit-var/imm32/inouts
12255     0/imm32/no-outputs
12256     0/imm32/no-outputs
12257     0x11/imm32/alloc-id:fake
12258     _string_0f_8d_jump_label/imm32/subx-name
12259     0/imm32/no-rm32
12260     0/imm32/no-r32
12261     0/imm32/no-imm32
12262     1/imm32/disp32-is-first-inout
12263     0/imm32/no-output
12264     0x11/imm32/alloc-id:fake
12265     _Primitive-break-if-<=-named/imm32/next
12266 _Primitive-break-if-<=-named:  # (payload primitive)
12267     0x11/imm32/alloc-id:fake:payload
12268     0x11/imm32/alloc-id:fake
12269     _string-break-if-<=/imm32/name
12270     0x11/imm32/alloc-id:fake
12271     Single-lit-var/imm32/inouts
12272     0/imm32/no-outputs
12273     0/imm32/no-outputs
12274     0x11/imm32/alloc-id:fake
12275     _string_0f_8e_jump_label/imm32/subx-name
12276     0/imm32/no-rm32
12277     0/imm32/no-r32
12278     0/imm32/no-imm32
12279     1/imm32/disp32-is-first-inout
12280     0/imm32/no-output
12281     0x11/imm32/alloc-id:fake
12282     _Primitive-break-if->-named/imm32/next
12283 _Primitive-break-if->-named:  # (payload primitive)
12284     0x11/imm32/alloc-id:fake:payload
12285     0x11/imm32/alloc-id:fake
12286     _string-break-if->/imm32/name
12287     0x11/imm32/alloc-id:fake
12288     Single-lit-var/imm32/inouts
12289     0/imm32/no-outputs
12290     0/imm32/no-outputs
12291     0x11/imm32/alloc-id:fake
12292     _string_0f_8f_jump_label/imm32/subx-name
12293     0/imm32/no-rm32
12294     0/imm32/no-r32
12295     0/imm32/no-imm32
12296     1/imm32/disp32-is-first-inout
12297     0/imm32/no-output
12298     0x11/imm32/alloc-id:fake
12299     _Primitive-break-named/imm32/next
12300 _Primitive-break-named:  # (payload primitive)
12301     0x11/imm32/alloc-id:fake:payload
12302     0x11/imm32/alloc-id:fake
12303     _string-break/imm32/name
12304     0x11/imm32/alloc-id:fake
12305     Single-lit-var/imm32/inouts
12306     0/imm32/no-outputs
12307     0/imm32/no-outputs
12308     0x11/imm32/alloc-id:fake
12309     _string_e9_jump_label/imm32/subx-name
12310     0/imm32/no-rm32
12311     0/imm32/no-r32
12312     0/imm32/no-imm32
12313     1/imm32/disp32-is-first-inout
12314     0/imm32/no-output
12315     0x11/imm32/alloc-id:fake
12316     _Primitive-loop-if-addr<-named/imm32/next
12317 _Primitive-loop-if-addr<-named:  # (payload primitive)
12318     0x11/imm32/alloc-id:fake:payload
12319     0x11/imm32/alloc-id:fake
12320     _string-loop-if-addr</imm32/name
12321     0x11/imm32/alloc-id:fake
12322     Single-lit-var/imm32/inouts
12323     0/imm32/no-outputs
12324     0/imm32/no-outputs
12325     0x11/imm32/alloc-id:fake
12326     _string_0f_82_jump_label/imm32/subx-name
12327     0/imm32/no-rm32
12328     0/imm32/no-r32
12329     0/imm32/no-imm32
12330     1/imm32/disp32-is-first-inout
12331     0/imm32/no-output
12332     0x11/imm32/alloc-id:fake
12333     _Primitive-loop-if-addr>=-named/imm32/next
12334 _Primitive-loop-if-addr>=-named:  # (payload primitive)
12335     0x11/imm32/alloc-id:fake:payload
12336     0x11/imm32/alloc-id:fake
12337     _string-loop-if-addr>=/imm32/name
12338     0x11/imm32/alloc-id:fake
12339     Single-lit-var/imm32/inouts
12340     0/imm32/no-outputs
12341     0/imm32/no-outputs
12342     0x11/imm32/alloc-id:fake
12343     _string_0f_83_jump_label/imm32/subx-name
12344     0/imm32/no-rm32
12345     0/imm32/no-r32
12346     0/imm32/no-imm32
12347     1/imm32/disp32-is-first-inout
12348     0/imm32/no-output
12349     0x11/imm32/alloc-id:fake
12350     _Primitive-loop-if-=-named/imm32/next
12351 _Primitive-loop-if-=-named:  # (payload primitive)
12352     0x11/imm32/alloc-id:fake:payload
12353     0x11/imm32/alloc-id:fake
12354     _string-loop-if-=/imm32/name
12355     0x11/imm32/alloc-id:fake
12356     Single-lit-var/imm32/inouts
12357     0/imm32/no-outputs
12358     0/imm32/no-outputs
12359     0x11/imm32/alloc-id:fake
12360     _string_0f_84_jump_label/imm32/subx-name
12361     0/imm32/no-rm32
12362     0/imm32/no-r32
12363     0/imm32/no-imm32
12364     1/imm32/disp32-is-first-inout
12365     0/imm32/no-output
12366     0x11/imm32/alloc-id:fake
12367     _Primitive-loop-if-!=-named/imm32/next
12368 _Primitive-loop-if-!=-named:  # (payload primitive)
12369     0x11/imm32/alloc-id:fake:payload
12370     0x11/imm32/alloc-id:fake
12371     _string-loop-if-!=/imm32/name
12372     0x11/imm32/alloc-id:fake
12373     Single-lit-var/imm32/inouts
12374     0/imm32/no-outputs
12375     0/imm32/no-outputs
12376     0x11/imm32/alloc-id:fake
12377     _string_0f_85_jump_label/imm32/subx-name
12378     0/imm32/no-rm32
12379     0/imm32/no-r32
12380     0/imm32/no-imm32
12381     1/imm32/disp32-is-first-inout
12382     0/imm32/no-output
12383     0x11/imm32/alloc-id:fake
12384     _Primitive-loop-if-addr<=-named/imm32/next
12385 _Primitive-loop-if-addr<=-named:  # (payload primitive)
12386     0x11/imm32/alloc-id:fake:payload
12387     0x11/imm32/alloc-id:fake
12388     _string-loop-if-addr<=/imm32/name
12389     0x11/imm32/alloc-id:fake
12390     Single-lit-var/imm32/inouts
12391     0/imm32/no-outputs
12392     0/imm32/no-outputs
12393     0x11/imm32/alloc-id:fake
12394     _string_0f_86_jump_label/imm32/subx-name
12395     0/imm32/no-rm32
12396     0/imm32/no-r32
12397     0/imm32/no-imm32
12398     1/imm32/disp32-is-first-inout
12399     0/imm32/no-output
12400     0x11/imm32/alloc-id:fake
12401     _Primitive-loop-if-addr>-named/imm32/next
12402 _Primitive-loop-if-addr>-named:  # (payload primitive)
12403     0x11/imm32/alloc-id:fake:payload
12404     0x11/imm32/alloc-id:fake
12405     _string-loop-if-addr>/imm32/name
12406     0x11/imm32/alloc-id:fake
12407     Single-lit-var/imm32/inouts
12408     0/imm32/no-outputs
12409     0/imm32/no-outputs
12410     0x11/imm32/alloc-id:fake
12411     _string_0f_87_jump_label/imm32/subx-name
12412     0/imm32/no-rm32
12413     0/imm32/no-r32
12414     0/imm32/no-imm32
12415     1/imm32/disp32-is-first-inout
12416     0/imm32/no-output
12417     0x11/imm32/alloc-id:fake
12418     _Primitive-loop-if-<-named/imm32/next
12419 _Primitive-loop-if-<-named:  # (payload primitive)
12420     0x11/imm32/alloc-id:fake:payload
12421     0x11/imm32/alloc-id:fake
12422     _string-loop-if-</imm32/name
12423     0x11/imm32/alloc-id:fake
12424     Single-lit-var/imm32/inouts
12425     0/imm32/no-outputs
12426     0/imm32/no-outputs
12427     0x11/imm32/alloc-id:fake
12428     _string_0f_8c_jump_label/imm32/subx-name
12429     0/imm32/no-rm32
12430     0/imm32/no-r32
12431     0/imm32/no-imm32
12432     1/imm32/disp32-is-first-inout
12433     0/imm32/no-output
12434     0x11/imm32/alloc-id:fake
12435     _Primitive-loop-if->=-named/imm32/next
12436 _Primitive-loop-if->=-named:  # (payload primitive)
12437     0x11/imm32/alloc-id:fake:payload
12438     0x11/imm32/alloc-id:fake
12439     _string-loop-if->=/imm32/name
12440     0x11/imm32/alloc-id:fake
12441     Single-lit-var/imm32/inouts
12442     0/imm32/no-outputs
12443     0/imm32/no-outputs
12444     0x11/imm32/alloc-id:fake
12445     _string_0f_8d_jump_label/imm32/subx-name
12446     0/imm32/no-rm32
12447     0/imm32/no-r32
12448     0/imm32/no-imm32
12449     1/imm32/disp32-is-first-inout
12450     0/imm32/no-output
12451     0x11/imm32/alloc-id:fake
12452     _Primitive-loop-if-<=-named/imm32/next
12453 _Primitive-loop-if-<=-named:  # (payload primitive)
12454     0x11/imm32/alloc-id:fake:payload
12455     0x11/imm32/alloc-id:fake
12456     _string-loop-if-<=/imm32/name
12457     0x11/imm32/alloc-id:fake
12458     Single-lit-var/imm32/inouts
12459     0/imm32/no-outputs
12460     0/imm32/no-outputs
12461     0x11/imm32/alloc-id:fake
12462     _string_0f_8e_jump_label/imm32/subx-name
12463     0/imm32/no-rm32
12464     0/imm32/no-r32
12465     0/imm32/no-imm32
12466     1/imm32/disp32-is-first-inout
12467     0/imm32/no-output
12468     0x11/imm32/alloc-id:fake
12469     _Primitive-loop-if->-named/imm32/next
12470 _Primitive-loop-if->-named:  # (payload primitive)
12471     0x11/imm32/alloc-id:fake:payload
12472     0x11/imm32/alloc-id:fake
12473     _string-loop-if->/imm32/name
12474     0x11/imm32/alloc-id:fake
12475     Single-lit-var/imm32/inouts
12476     0/imm32/no-outputs
12477     0/imm32/no-outputs
12478     0x11/imm32/alloc-id:fake
12479     _string_0f_8f_jump_label/imm32/subx-name
12480     0/imm32/no-rm32
12481     0/imm32/no-r32
12482     0/imm32/no-imm32
12483     1/imm32/disp32-is-first-inout
12484     0/imm32/no-output
12485     0x11/imm32/alloc-id:fake
12486     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
12487 _Primitive-loop-named:  # (payload primitive)
12488     0x11/imm32/alloc-id:fake:payload
12489     0x11/imm32/alloc-id:fake
12490     _string-loop/imm32/name
12491     0x11/imm32/alloc-id:fake
12492     Single-lit-var/imm32/inouts
12493     0/imm32/no-outputs
12494     0/imm32/no-outputs
12495     0x11/imm32/alloc-id:fake
12496     _string_e9_jump_label/imm32/subx-name
12497     0/imm32/no-rm32
12498     0/imm32/no-r32
12499     0/imm32/no-imm32
12500     1/imm32/disp32-is-first-inout
12501     0/imm32/no-output
12502     0/imm32/next
12503     0/imm32/next
12504 
12505 # string literals for Mu instructions
12506 _string-add:  # (payload array byte)
12507     0x11/imm32/alloc-id:fake:payload
12508     # "add"
12509     0x3/imm32/size
12510     0x61/a 0x64/d 0x64/d
12511 _string-address:  # (payload array byte)
12512     0x11/imm32/alloc-id:fake:payload
12513     # "address"
12514     0x7/imm32/size
12515     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
12516 _string-add-to:  # (payload array byte)
12517     0x11/imm32/alloc-id:fake:payload
12518     # "add-to"
12519     0x6/imm32/size
12520     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
12521 _string-and:  # (payload array byte)
12522     0x11/imm32/alloc-id:fake:payload
12523     # "and"
12524     0x3/imm32/size
12525     0x61/a 0x6e/n 0x64/d
12526 _string-and-with:  # (payload array byte)
12527     0x11/imm32/alloc-id:fake:payload
12528     # "and-with"
12529     0x8/imm32/size
12530     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12531 _string-break:  # (payload array byte)
12532     0x11/imm32/alloc-id:fake:payload
12533     # "break"
12534     0x5/imm32/size
12535     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
12536 _string-break-if-<:  # (payload array byte)
12537     0x11/imm32/alloc-id:fake:payload
12538     # "break-if-<"
12539     0xa/imm32/size
12540     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
12541 _string-break-if-<=:  # (payload array byte)
12542     0x11/imm32/alloc-id:fake:payload
12543     # "break-if-<="
12544     0xb/imm32/size
12545     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
12546 _string-break-if-=:  # (payload array byte)
12547     0x11/imm32/alloc-id:fake:payload
12548     # "break-if-="
12549     0xa/imm32/size
12550     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
12551 _string-break-if->:  # (payload array byte)
12552     0x11/imm32/alloc-id:fake:payload
12553     # "break-if->"
12554     0xa/imm32/size
12555     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
12556 _string-break-if->=:  # (payload array byte)
12557     0x11/imm32/alloc-id:fake:payload
12558     # "break-if->="
12559     0xb/imm32/size
12560     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
12561 _string-break-if-!=:  # (payload array byte)
12562     0x11/imm32/alloc-id:fake:payload
12563     # "break-if-!="
12564     0xb/imm32/size
12565     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
12566 _string-break-if-addr<:  # (payload array byte)
12567     0x11/imm32/alloc-id:fake:payload
12568     # "break-if-addr<"
12569     0xe/imm32/size
12570     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/<
12571 _string-break-if-addr<=:  # (payload array byte)
12572     0x11/imm32/alloc-id:fake:payload
12573     # "break-if-addr<="
12574     0xf/imm32/size
12575     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/=
12576 _string-break-if-addr>:  # (payload array byte)
12577     0x11/imm32/alloc-id:fake:payload
12578     # "break-if-addr>"
12579     0xe/imm32/size
12580     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/>
12581 _string-break-if-addr>=:  # (payload array byte)
12582     0x11/imm32/alloc-id:fake:payload
12583     # "break-if-addr>="
12584     0xf/imm32/size
12585     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/=
12586 _string-compare:  # (payload array byte)
12587     0x11/imm32/alloc-id:fake:payload
12588     # "compare"
12589     0x7/imm32/size
12590     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
12591 _string-copy:  # (payload array byte)
12592     0x11/imm32/alloc-id:fake:payload
12593     # "copy"
12594     0x4/imm32/size
12595     0x63/c 0x6f/o 0x70/p 0x79/y
12596 _string-copy-to:  # (payload array byte)
12597     0x11/imm32/alloc-id:fake:payload
12598     # "copy-to"
12599     0x7/imm32/size
12600     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
12601 _string-copy-byte:
12602     0x11/imm32/alloc-id:fake:payload
12603     # "copy-byte"
12604     0x9/imm32/size
12605     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
12606 _string-copy-byte-to:
12607     0x11/imm32/alloc-id:fake:payload
12608     # "copy-byte-to"
12609     0xc/imm32/size
12610     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
12611 _string-decrement:  # (payload array byte)
12612     0x11/imm32/alloc-id:fake:payload
12613     # "decrement"
12614     0x9/imm32/size
12615     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12616 _string-increment:  # (payload array byte)
12617     0x11/imm32/alloc-id:fake:payload
12618     # "increment"
12619     0x9/imm32/size
12620     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
12621 _string-loop:  # (payload array byte)
12622     0x11/imm32/alloc-id:fake:payload
12623     # "loop"
12624     0x4/imm32/size
12625     0x6c/l 0x6f/o 0x6f/o 0x70/p
12626 _string-loop-if-<:  # (payload array byte)
12627     0x11/imm32/alloc-id:fake:payload
12628     # "loop-if-<"
12629     0x9/imm32/size
12630     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
12631 _string-loop-if-<=:  # (payload array byte)
12632     0x11/imm32/alloc-id:fake:payload
12633     # "loop-if-<="
12634     0xa/imm32/size
12635     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
12636 _string-loop-if-=:  # (payload array byte)
12637     0x11/imm32/alloc-id:fake:payload
12638     # "loop-if-="
12639     0x9/imm32/size
12640     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
12641 _string-loop-if->:  # (payload array byte)
12642     0x11/imm32/alloc-id:fake:payload
12643     # "loop-if->"
12644     0x9/imm32/size
12645     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
12646 _string-loop-if->=:  # (payload array byte)
12647     0x11/imm32/alloc-id:fake:payload
12648     # "loop-if->="
12649     0xa/imm32/size
12650     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
12651 _string-loop-if-!=:  # (payload array byte)
12652     0x11/imm32/alloc-id:fake:payload
12653     # "loop-if-!="
12654     0xa/imm32/size
12655     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
12656 _string-loop-if-addr<:  # (payload array byte)
12657     0x11/imm32/alloc-id:fake:payload
12658     # "loop-if-addr<"
12659     0xd/imm32/size
12660     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/<
12661 _string-loop-if-addr<=:  # (payload array byte)
12662     0x11/imm32/alloc-id:fake:payload
12663     # "loop-if-addr<="
12664     0xe/imm32/size
12665     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/=
12666 _string-loop-if-addr>:  # (payload array byte)
12667     0x11/imm32/alloc-id:fake:payload
12668     # "loop-if-addr>"
12669     0xd/imm32/size
12670     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/>
12671 _string-loop-if-addr>=:  # (payload array byte)
12672     0x11/imm32/alloc-id:fake:payload
12673     # "loop-if-addr>="
12674     0xe/imm32/size
12675     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/=
12676 _string-multiply:  # (payload array byte)
12677     0x11/imm32/alloc-id:fake:payload
12678     # "multiply"
12679     0x8/imm32/size
12680     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
12681 _string-or:  # (payload array byte)
12682     0x11/imm32/alloc-id:fake:payload
12683     # "or"
12684     0x2/imm32/size
12685     0x6f/o 0x72/r
12686 _string-or-with:  # (payload array byte)
12687     0x11/imm32/alloc-id:fake:payload
12688     # "or-with"
12689     0x7/imm32/size
12690     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12691 _string-subtract:  # (payload array byte)
12692     0x11/imm32/alloc-id:fake:payload
12693     # "subtract"
12694     0x8/imm32/size
12695     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12696 _string-subtract-from:  # (payload array byte)
12697     0x11/imm32/alloc-id:fake:payload
12698     # "subtract-from"
12699     0xd/imm32/size
12700     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
12701 _string-xor:  # (payload array byte)
12702     0x11/imm32/alloc-id:fake:payload
12703     # "xor"
12704     0x3/imm32/size
12705     0x78/x 0x6f/o 0x72/r
12706 _string-xor-with:  # (payload array byte)
12707     0x11/imm32/alloc-id:fake:payload
12708     # "xor-with"
12709     0x8/imm32/size
12710     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12711 
12712 # string literals for SubX instructions
12713 _string_01_add_to:  # (payload array byte)
12714     0x11/imm32/alloc-id:fake:payload
12715     # "01/add-to"
12716     0x9/imm32/size
12717     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
12718 _string_03_add:  # (payload array byte)
12719     0x11/imm32/alloc-id:fake:payload
12720     # "03/add"
12721     0x6/imm32/size
12722     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
12723 _string_05_add_to_eax:  # (payload array byte)
12724     0x11/imm32/alloc-id:fake:payload
12725     # "05/add-to-eax"
12726     0xd/imm32/size
12727     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
12728 _string_09_or_with:  # (payload array byte)
12729     0x11/imm32/alloc-id:fake:payload
12730     # "09/or-with"
12731     0xa/imm32/size
12732     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12733 _string_0b_or:  # (payload array byte)
12734     0x11/imm32/alloc-id:fake:payload
12735     # "0b/or"
12736     0x5/imm32/size
12737     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
12738 _string_0d_or_with_eax:  # (payload array byte)
12739     0x11/imm32/alloc-id:fake:payload
12740     # "0d/or-with-eax"
12741     0xe/imm32/size
12742     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
12743 _string_0f_82_jump_label:  # (payload array byte)
12744     0x11/imm32/alloc-id:fake:payload
12745     # "0f 82/jump-if-addr<"
12746     0x13/imm32/size
12747     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/<
12748 _string_0f_82_jump_break:  # (payload array byte)
12749     0x11/imm32/alloc-id:fake:payload
12750     # "0f 82/jump-if-addr< break/disp32"
12751     0x20/imm32/size
12752     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
12753 _string_0f_82_jump_loop:  # (payload array byte)
12754     0x11/imm32/alloc-id:fake:payload
12755     # "0f 82/jump-if-addr< loop/disp32"
12756     0x1f/imm32/size
12757     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
12758 _string_0f_83_jump_label:  # (payload array byte)
12759     0x11/imm32/alloc-id:fake:payload
12760     # "0f 83/jump-if-addr>="
12761     0x14/imm32/size
12762     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/=
12763 _string_0f_83_jump_break:  # (payload array byte)
12764     0x11/imm32/alloc-id:fake:payload
12765     # "0f 83/jump-if-addr>= break/disp32"
12766     0x21/imm32/size
12767     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
12768 _string_0f_83_jump_loop:  # (payload array byte)
12769     0x11/imm32/alloc-id:fake:payload
12770     # "0f 83/jump-if-addr>= loop/disp32"
12771     0x20/imm32/size
12772     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
12773 _string_0f_84_jump_label:  # (payload array byte)
12774     0x11/imm32/alloc-id:fake:payload
12775     # "0f 84/jump-if-="
12776     0xf/imm32/size
12777     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/=
12778 _string_0f_84_jump_break:  # (payload array byte)
12779     0x11/imm32/alloc-id:fake:payload
12780     # "0f 84/jump-if-= break/disp32"
12781     0x1c/imm32/size
12782     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
12783 _string_0f_84_jump_loop:  # (payload array byte)
12784     0x11/imm32/alloc-id:fake:payload
12785     # "0f 84/jump-if-= loop/disp32"
12786     0x1b/imm32/size
12787     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
12788 _string_0f_85_jump_label:  # (payload array byte)
12789     0x11/imm32/alloc-id:fake:payload
12790     # "0f 85/jump-if-!="
12791     0x10/imm32/size
12792     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/=
12793 _string_0f_85_jump_break:  # (payload array byte)
12794     0x11/imm32/alloc-id:fake:payload
12795     # "0f 85/jump-if-!= break/disp32"
12796     0x1d/imm32/size
12797     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
12798 _string_0f_85_jump_loop:  # (payload array byte)
12799     0x11/imm32/alloc-id:fake:payload
12800     # "0f 85/jump-if-!= loop/disp32"
12801     0x1c/imm32/size
12802     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
12803 _string_0f_86_jump_label:  # (payload array byte)
12804     0x11/imm32/alloc-id:fake:payload
12805     # "0f 86/jump-if-addr<="
12806     0x14/imm32/size
12807     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/=
12808 _string_0f_86_jump_break:  # (payload array byte)
12809     0x11/imm32/alloc-id:fake:payload
12810     # "0f 86/jump-if-addr<= break/disp32"
12811     0x21/imm32/size
12812     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
12813 _string_0f_86_jump_loop:  # (payload array byte)
12814     0x11/imm32/alloc-id:fake:payload
12815     # "0f 86/jump-if-addr<= loop/disp32"
12816     0x20/imm32/size
12817     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
12818 _string_0f_87_jump_label:  # (payload array byte)
12819     0x11/imm32/alloc-id:fake:payload
12820     # "0f 87/jump-if-addr>"
12821     0x13/imm32/size
12822     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/>
12823 _string_0f_87_jump_break:  # (payload array byte)
12824     0x11/imm32/alloc-id:fake:payload
12825     # "0f 87/jump-if-addr> break/disp32"
12826     0x20/imm32/size
12827     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
12828 _string_0f_87_jump_loop:  # (payload array byte)
12829     0x11/imm32/alloc-id:fake:payload
12830     # "0f 87/jump-if-addr> loop/disp32"
12831     0x1f/imm32/size
12832     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
12833 _string_0f_8c_jump_label:  # (payload array byte)
12834     0x11/imm32/alloc-id:fake:payload
12835     # "0f 8c/jump-if-<"
12836     0xf/imm32/size
12837     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/<
12838 _string_0f_8c_jump_break:  # (payload array byte)
12839     0x11/imm32/alloc-id:fake:payload
12840     # "0f 8c/jump-if-< break/disp32"
12841     0x1c/imm32/size
12842     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
12843 _string_0f_8c_jump_loop:  # (payload array byte)
12844     0x11/imm32/alloc-id:fake:payload
12845     # "0f 8c/jump-if-< loop/disp32"
12846     0x1b/imm32/size
12847     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
12848 _string_0f_8d_jump_label:  # (payload array byte)
12849     0x11/imm32/alloc-id:fake:payload
12850     # "0f 8d/jump-if->="
12851     0x10/imm32/size
12852     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/=
12853 _string_0f_8d_jump_break:  # (payload array byte)
12854     0x11/imm32/alloc-id:fake:payload
12855     # "0f 8d/jump-if->= break/disp32"
12856     0x1d/imm32/size
12857     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
12858 _string_0f_8d_jump_loop:  # (payload array byte)
12859     0x11/imm32/alloc-id:fake:payload
12860     # "0f 8d/jump-if->= loop/disp32"
12861     0x1c/imm32/size
12862     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
12863 _string_0f_8e_jump_label:  # (payload array byte)
12864     0x11/imm32/alloc-id:fake:payload
12865     # "0f 8e/jump-if-<="
12866     0x10/imm32/size
12867     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/=
12868 _string_0f_8e_jump_break:  # (payload array byte)
12869     0x11/imm32/alloc-id:fake:payload
12870     # "0f 8e/jump-if-<= break/disp32"
12871     0x1d/imm32/size
12872     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
12873 _string_0f_8e_jump_loop:  # (payload array byte)
12874     0x11/imm32/alloc-id:fake:payload
12875     # "0f 8e/jump-if-<= loop/disp32"
12876     0x1c/imm32/size
12877     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
12878 _string_0f_8f_jump_label:  # (payload array byte)
12879     0x11/imm32/alloc-id:fake:payload
12880     # "0f 8f/jump-if->"
12881     0xf/imm32/size
12882     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/>
12883 _string_0f_8f_jump_break:  # (payload array byte)
12884     0x11/imm32/alloc-id:fake:payload
12885     # "0f 8f/jump-if-> break/disp32"
12886     0x1c/imm32/size
12887     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
12888 _string_0f_8f_jump_loop:  # (payload array byte)
12889     0x11/imm32/alloc-id:fake:payload
12890     # "0f 8f/jump-if-> loop/disp32"
12891     0x1b/imm32/size
12892     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
12893 _string_0f_af_multiply:  # (payload array byte)
12894     0x11/imm32/alloc-id:fake:payload
12895     # "0f af/multiply"
12896     0xe/imm32/size
12897     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
12898 _string_21_and_with:  # (payload array byte)
12899     0x11/imm32/alloc-id:fake:payload
12900     # "21/and-with"
12901     0xb/imm32/size
12902     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12903 _string_23_and:  # (payload array byte)
12904     0x11/imm32/alloc-id:fake:payload
12905     # "23/and"
12906     0x6/imm32/size
12907     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
12908 _string_25_and_with_eax:  # (payload array byte)
12909     0x11/imm32/alloc-id:fake:payload
12910     # "25/and-with-eax"
12911     0xf/imm32/size
12912     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
12913 _string_29_subtract_from:  # (payload array byte)
12914     0x11/imm32/alloc-id:fake:payload
12915     # "29/subtract-from"
12916     0x10/imm32/size
12917     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
12918 _string_2b_subtract:  # (payload array byte)
12919     0x11/imm32/alloc-id:fake:payload
12920     # "2b/subtract"
12921     0xb/imm32/size
12922     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
12923 _string_2d_subtract_from_eax:  # (payload array byte)
12924     0x11/imm32/alloc-id:fake:payload
12925     # "2d/subtract-from-eax"
12926     0x14/imm32/size
12927     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
12928 _string_31_xor_with:  # (payload array byte)
12929     0x11/imm32/alloc-id:fake:payload
12930     # "31/xor-with"
12931     0xb/imm32/size
12932     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
12933 _string_33_xor:  # (payload array byte)
12934     0x11/imm32/alloc-id:fake:payload
12935     # "33/xor"
12936     0x6/imm32/size
12937     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
12938 _string_35_xor_with_eax:  # (payload array byte)
12939     0x11/imm32/alloc-id:fake:payload
12940     # "35/xor-with-eax"
12941     0xf/imm32/size
12942     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
12943 _string_39_compare->:  # (payload array byte)
12944     0x11/imm32/alloc-id:fake:payload
12945     # "39/compare->"
12946     0xc/imm32/size
12947     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
12948 _string_3b_compare<-:  # (payload array byte)
12949     0x11/imm32/alloc-id:fake:payload
12950     # "3b/compare<-"
12951     0xc/imm32/size
12952     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
12953 _string_3d_compare_eax_with:  # (payload array byte)
12954     0x11/imm32/alloc-id:fake:payload
12955     # "3d/compare-eax-with"
12956     0x13/imm32/size
12957     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
12958 _string_40_increment_eax:  # (payload array byte)
12959     0x11/imm32/alloc-id:fake:payload
12960     # "40/increment-eax"
12961     0x10/imm32/size
12962     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
12963 _string_41_increment_ecx:  # (payload array byte)
12964     0x11/imm32/alloc-id:fake:payload
12965     # "41/increment-ecx"
12966     0x10/imm32/size
12967     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
12968 _string_42_increment_edx:  # (payload array byte)
12969     0x11/imm32/alloc-id:fake:payload
12970     # "42/increment-edx"
12971     0x10/imm32/size
12972     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
12973 _string_43_increment_ebx:  # (payload array byte)
12974     0x11/imm32/alloc-id:fake:payload
12975     # "43/increment-ebx"
12976     0x10/imm32/size
12977     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
12978 _string_46_increment_esi:  # (payload array byte)
12979     0x11/imm32/alloc-id:fake:payload
12980     # "46/increment-esi"
12981     0x10/imm32/size
12982     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
12983 _string_47_increment_edi:  # (payload array byte)
12984     0x11/imm32/alloc-id:fake:payload
12985     # "47/increment-edi"
12986     0x10/imm32/size
12987     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
12988 _string_48_decrement_eax:  # (payload array byte)
12989     0x11/imm32/alloc-id:fake:payload
12990     # "48/decrement-eax"
12991     0x10/imm32/size
12992     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
12993 _string_49_decrement_ecx:  # (payload array byte)
12994     0x11/imm32/alloc-id:fake:payload
12995     # "49/decrement-ecx"
12996     0x10/imm32/size
12997     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
12998 _string_4a_decrement_edx:  # (payload array byte)
12999     0x11/imm32/alloc-id:fake:payload
13000     # "4a/decrement-edx"
13001     0x10/imm32/size
13002     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
13003 _string_4b_decrement_ebx:  # (payload array byte)
13004     0x11/imm32/alloc-id:fake:payload
13005     # "4b/decrement-ebx"
13006     0x10/imm32/size
13007     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
13008 _string_4e_decrement_esi:  # (payload array byte)
13009     0x11/imm32/alloc-id:fake:payload
13010     # "4e/decrement-esi"
13011     0x10/imm32/size
13012     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
13013 _string_4f_decrement_edi:  # (payload array byte)
13014     0x11/imm32/alloc-id:fake:payload
13015     # "4f/decrement-edi"
13016     0x10/imm32/size
13017     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
13018 _string_81_subop_add:  # (payload array byte)
13019     0x11/imm32/alloc-id:fake:payload
13020     # "81 0/subop/add"
13021     0xe/imm32/size
13022     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
13023 _string_81_subop_or:  # (payload array byte)
13024     0x11/imm32/alloc-id:fake:payload
13025     # "81 1/subop/or"
13026     0xd/imm32/size
13027     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
13028 _string_81_subop_and:  # (payload array byte)
13029     0x11/imm32/alloc-id:fake:payload
13030     # "81 4/subop/and"
13031     0xe/imm32/size
13032     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
13033 _string_81_subop_subtract:  # (payload array byte)
13034     0x11/imm32/alloc-id:fake:payload
13035     # "81 5/subop/subtract"
13036     0x13/imm32/size
13037     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
13038 _string_81_subop_xor:  # (payload array byte)
13039     0x11/imm32/alloc-id:fake:payload
13040     # "81 6/subop/xor"
13041     0xe/imm32/size
13042     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
13043 _string_81_subop_compare:  # (payload array byte)
13044     0x11/imm32/alloc-id:fake:payload
13045     # "81 7/subop/compare"
13046     0x12/imm32/size
13047     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
13048 _string_89_<-:  # (payload array byte)
13049     0x11/imm32/alloc-id:fake:payload
13050     # "89/<-"
13051     0x5/imm32/size
13052     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
13053 _string_8b_->:  # (payload array byte)
13054     0x11/imm32/alloc-id:fake:payload
13055     # "8b/->"
13056     0x5/imm32/size
13057     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
13058 _string_8a_copy_byte:
13059     0x11/imm32/alloc-id:fake:payload
13060     # "8a/byte->"
13061     0x9/imm32/size
13062     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
13063 _string_88_copy_byte:
13064     0x11/imm32/alloc-id:fake:payload
13065     # "88/byte<-"
13066     0x9/imm32/size
13067     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
13068 _string_8d_copy_address:  # (payload array byte)
13069     0x11/imm32/alloc-id:fake:payload
13070     # "8d/copy-address"
13071     0xf/imm32/size
13072     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
13073 _string_b8_copy_to_eax:  # (payload array byte)
13074     0x11/imm32/alloc-id:fake:payload
13075     # "b8/copy-to-eax"
13076     0xe/imm32/size
13077     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
13078 _string_b9_copy_to_ecx:  # (payload array byte)
13079     0x11/imm32/alloc-id:fake:payload
13080     # "b9/copy-to-ecx"
13081     0xe/imm32/size
13082     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
13083 _string_ba_copy_to_edx:  # (payload array byte)
13084     0x11/imm32/alloc-id:fake:payload
13085     # "ba/copy-to-edx"
13086     0xe/imm32/size
13087     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
13088 _string_bb_copy_to_ebx:  # (payload array byte)
13089     0x11/imm32/alloc-id:fake:payload
13090     # "bb/copy-to-ebx"
13091     0xe/imm32/size
13092     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
13093 _string_be_copy_to_esi:  # (payload array byte)
13094     0x11/imm32/alloc-id:fake:payload
13095     # "be/copy-to-esi"
13096     0xe/imm32/size
13097     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
13098 _string_bf_copy_to_edi:  # (payload array byte)
13099     0x11/imm32/alloc-id:fake:payload
13100     # "bf/copy-to-edi"
13101     0xe/imm32/size
13102     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
13103 _string_c7_subop_copy:  # (payload array byte)
13104     0x11/imm32/alloc-id:fake:payload
13105     # "c7 0/subop/copy"
13106     0xf/imm32/size
13107     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
13108 _string_e9_jump_label:  # (payload array byte)
13109     0x11/imm32/alloc-id:fake:payload
13110     # "e9/jump"
13111     0x7/imm32/size
13112     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
13113 _string_e9_jump_break:  # (payload array byte)
13114     0x11/imm32/alloc-id:fake:payload
13115     # "e9/jump break/disp32"
13116     0x14/imm32/size
13117     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
13118 _string_e9_jump_loop:  # (payload array byte)
13119     0x11/imm32/alloc-id:fake:payload
13120     # "e9/jump loop/disp32"
13121     0x13/imm32/size
13122     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
13123 _string_ff_subop_increment:  # (payload array byte)
13124     0x11/imm32/alloc-id:fake:payload
13125     # "ff 0/subop/increment"
13126     0x14/imm32/size
13127     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
13128 _string_ff_subop_decrement:  # (payload array byte)
13129     0x11/imm32/alloc-id:fake:payload
13130     # "ff 1/subop/decrement"
13131     0x14/imm32/size
13132     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
13133 
13134 Single-int-var-in-mem:  # (payload list var)
13135     0x11/imm32/alloc-id:fake:payload
13136     0x11/imm32/alloc-id:fake
13137     Int-var-in-mem/imm32
13138     0/imm32/next
13139     0/imm32/next
13140 
13141 Int-var-in-mem:  # (payload var)
13142     0x11/imm32/alloc-id:fake:payload
13143     0/imm32/name
13144     0/imm32/name
13145     0x11/imm32/alloc-id:fake
13146     Type-int/imm32
13147     1/imm32/some-block-depth
13148     1/imm32/some-stack-offset
13149     0/imm32/no-register
13150     0/imm32/no-register
13151 
13152 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
13153 Single-byte-var-in-mem:  # (payload list var)
13154     0x11/imm32/alloc-id:fake:payload
13155     0x11/imm32/alloc-id:fake
13156     Byte-var-in-mem/imm32
13157     0/imm32/next
13158     0/imm32/next
13159 
13160 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
13161 Byte-var-in-mem:  # (payload var)
13162     0x11/imm32/alloc-id:fake:payload
13163     0/imm32/name
13164     0/imm32/name
13165     0x11/imm32/alloc-id:fake
13166     Type-byte/imm32
13167     1/imm32/some-block-depth
13168     1/imm32/some-stack-offset
13169     0/imm32/no-register
13170     0/imm32/no-register
13171 
13172 Two-args-int-stack-int-reg:  # (payload list var)
13173     0x11/imm32/alloc-id:fake:payload
13174     0x11/imm32/alloc-id:fake
13175     Int-var-in-mem/imm32
13176     0x11/imm32/alloc-id:fake
13177     Single-int-var-in-some-register/imm32/next
13178 
13179 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
13180 Two-args-byte-stack-byte-reg:  # (payload list var)
13181     0x11/imm32/alloc-id:fake:payload
13182     0x11/imm32/alloc-id:fake
13183     Byte-var-in-mem/imm32
13184     0x11/imm32/alloc-id:fake
13185     Single-byte-var-in-some-register/imm32/next
13186 
13187 Two-args-int-reg-int-stack:  # (payload list var)
13188     0x11/imm32/alloc-id:fake:payload
13189     0x11/imm32/alloc-id:fake
13190     Int-var-in-some-register/imm32
13191     0x11/imm32/alloc-id:fake
13192     Single-int-var-in-mem/imm32/next
13193 
13194 Two-args-int-eax-int-literal:  # (payload list var)
13195     0x11/imm32/alloc-id:fake:payload
13196     0x11/imm32/alloc-id:fake
13197     Int-var-in-eax/imm32
13198     0x11/imm32/alloc-id:fake
13199     Single-lit-var/imm32/next
13200 
13201 Int-var-and-literal:  # (payload list var)
13202     0x11/imm32/alloc-id:fake:payload
13203     0x11/imm32/alloc-id:fake
13204     Int-var-in-mem/imm32
13205     0x11/imm32/alloc-id:fake
13206     Single-lit-var/imm32/next
13207 
13208 Int-var-in-register-and-literal:  # (payload list var)
13209     0x11/imm32/alloc-id:fake:payload
13210     0x11/imm32/alloc-id:fake
13211     Int-var-in-some-register/imm32
13212     0x11/imm32/alloc-id:fake
13213     Single-lit-var/imm32/next
13214 
13215 Single-int-var-in-some-register:  # (payload list var)
13216     0x11/imm32/alloc-id:fake:payload
13217     0x11/imm32/alloc-id:fake
13218     Int-var-in-some-register/imm32
13219     0/imm32/next
13220     0/imm32/next
13221 
13222 Single-addr-var-in-some-register:  # (payload list var)
13223     0x11/imm32/alloc-id:fake:payload
13224     0x11/imm32/alloc-id:fake
13225     Addr-var-in-some-register/imm32
13226     0/imm32/next
13227     0/imm32/next
13228 
13229 Single-byte-var-in-some-register:  # (payload list var)
13230     0x11/imm32/alloc-id:fake:payload
13231     0x11/imm32/alloc-id:fake
13232     Byte-var-in-some-register/imm32
13233     0/imm32/next
13234     0/imm32/next
13235 
13236 Int-var-in-some-register:  # (payload var)
13237     0x11/imm32/alloc-id:fake:payload
13238     0/imm32/name
13239     0/imm32/name
13240     0x11/imm32/alloc-id:fake
13241     Type-int/imm32
13242     1/imm32/some-block-depth
13243     0/imm32/no-stack-offset
13244     0x11/imm32/alloc-id:fake
13245     Any-register/imm32
13246 
13247 Any-register:  # (payload array byte)
13248     0x11/imm32/alloc-id:fake:payload
13249     1/imm32/size
13250     # data
13251     2a/asterisk
13252 
13253 Addr-var-in-some-register:  # (payload var)
13254     0x11/imm32/alloc-id:fake:payload
13255     0/imm32/name
13256     0/imm32/name
13257     0x11/imm32/alloc-id:fake
13258     Type-addr/imm32
13259     1/imm32/some-block-depth
13260     0/imm32/no-stack-offset
13261     0x11/imm32/alloc-id:fake
13262     Any-register/imm32
13263 
13264 Byte-var-in-some-register:  # (payload var)
13265     0x11/imm32/alloc-id:fake:payload
13266     0/imm32/name
13267     0/imm32/name
13268     0x11/imm32/alloc-id:fake
13269     Type-byte/imm32
13270     1/imm32/some-block-depth
13271     0/imm32/no-stack-offset
13272     0x11/imm32/alloc-id:fake
13273     Any-register/imm32
13274 
13275 Single-int-var-in-eax:  # (payload list var)
13276     0x11/imm32/alloc-id:fake:payload
13277     0x11/imm32/alloc-id:fake
13278     Int-var-in-eax/imm32
13279     0/imm32/next
13280     0/imm32/next
13281 
13282 Int-var-in-eax:
13283     0x11/imm32/alloc-id:fake:payload
13284     0/imm32/name
13285     0/imm32/name
13286     0x11/imm32/alloc-id:fake
13287     Type-int/imm32
13288     1/imm32/some-block-depth
13289     0/imm32/no-stack-offset
13290     0x11/imm32/alloc-id:fake
13291     $Register-eax/imm32
13292 
13293 Single-int-var-in-ecx:  # (payload list var)
13294     0x11/imm32/alloc-id:fake:payload
13295     0x11/imm32/alloc-id:fake
13296     Int-var-in-ecx/imm32
13297     0/imm32/next
13298     0/imm32/next
13299 
13300 Int-var-in-ecx:
13301     0x11/imm32/alloc-id:fake:payload
13302     0/imm32/name
13303     0/imm32/name
13304     0x11/imm32/alloc-id:fake
13305     Type-int/imm32
13306     1/imm32/some-block-depth
13307     0/imm32/no-stack-offset
13308     0x11/imm32/alloc-id:fake
13309     $Register-ecx/imm32/register
13310 
13311 Single-int-var-in-edx:  # (payload list var)
13312     0x11/imm32/alloc-id:fake:payload
13313     0x11/imm32/alloc-id:fake
13314     Int-var-in-edx/imm32
13315     0/imm32/next
13316     0/imm32/next
13317 
13318 Int-var-in-edx:  # (payload list var)
13319     0x11/imm32/alloc-id:fake:payload
13320     0/imm32/name
13321     0/imm32/name
13322     0x11/imm32/alloc-id:fake
13323     Type-int/imm32
13324     1/imm32/some-block-depth
13325     0/imm32/no-stack-offset
13326     0x11/imm32/alloc-id:fake
13327     $Register-edx/imm32/register
13328 
13329 Single-int-var-in-ebx:  # (payload list var)
13330     0x11/imm32/alloc-id:fake:payload
13331     0x11/imm32/alloc-id:fake
13332     Int-var-in-ebx/imm32
13333     0/imm32/next
13334     0/imm32/next
13335 
13336 Int-var-in-ebx:  # (payload list var)
13337     0x11/imm32/alloc-id:fake:payload
13338     0/imm32/name
13339     0/imm32/name
13340     0x11/imm32/alloc-id:fake
13341     Type-int/imm32
13342     1/imm32/some-block-depth
13343     0/imm32/no-stack-offset
13344     0x11/imm32/alloc-id:fake
13345     $Register-ebx/imm32/register
13346 
13347 Single-int-var-in-esi:  # (payload list var)
13348     0x11/imm32/alloc-id:fake:payload
13349     0x11/imm32/alloc-id:fake
13350     Int-var-in-esi/imm32
13351     0/imm32/next
13352     0/imm32/next
13353 
13354 Int-var-in-esi:  # (payload list var)
13355     0x11/imm32/alloc-id:fake:payload
13356     0/imm32/name
13357     0/imm32/name
13358     0x11/imm32/alloc-id:fake
13359     Type-int/imm32
13360     1/imm32/some-block-depth
13361     0/imm32/no-stack-offset
13362     0x11/imm32/alloc-id:fake
13363     $Register-esi/imm32/register
13364 
13365 Single-int-var-in-edi:  # (payload list var)
13366     0x11/imm32/alloc-id:fake:payload
13367     0x11/imm32/alloc-id:fake
13368     Int-var-in-edi/imm32
13369     0/imm32/next
13370     0/imm32/next
13371 
13372 Int-var-in-edi:  # (payload list var)
13373     0x11/imm32/alloc-id:fake:payload
13374     0/imm32/name
13375     0/imm32/name
13376     0x11/imm32/alloc-id:fake
13377     Type-int/imm32
13378     1/imm32/some-block-depth
13379     0/imm32/no-stack-offset
13380     0x11/imm32/alloc-id:fake
13381     $Register-edi/imm32/register
13382 
13383 Single-lit-var:  # (payload list var)
13384     0x11/imm32/alloc-id:fake:payload
13385     0x11/imm32/alloc-id:fake
13386     Lit-var/imm32
13387     0/imm32/next
13388     0/imm32/next
13389 
13390 Lit-var:  # (payload var)
13391     0x11/imm32/alloc-id:fake:payload
13392     0/imm32/name
13393     0/imm32/name
13394     0x11/imm32/alloc-id:fake
13395     Type-literal/imm32
13396     1/imm32/some-block-depth
13397     0/imm32/no-stack-offset
13398     0/imm32/no-register
13399     0/imm32/no-register
13400 
13401 Type-int:  # (payload tree type-id)
13402     0x11/imm32/alloc-id:fake:payload
13403     1/imm32/left-is-atom
13404     1/imm32/value:int
13405     0/imm32/left:unused
13406     0/imm32/right:null
13407     0/imm32/right:null
13408 
13409 Type-literal:  # (payload tree type-id)
13410     0x11/imm32/alloc-id:fake:payload
13411     1/imm32/is-atom
13412     0/imm32/value:literal
13413     0/imm32/left:unused
13414     0/imm32/right:null
13415     0/imm32/right:null
13416 
13417 Type-addr:  # (payload tree type-id)
13418     0x11/imm32/alloc-id:fake:payload
13419     1/imm32/is-atom
13420     2/imm32/value:addr
13421     0/imm32/left:unused
13422     0/imm32/right:null
13423     0/imm32/right:null
13424 
13425 Type-byte:  # (payload tree type-id)
13426     0x11/imm32/alloc-id:fake:payload
13427     1/imm32/is-atom
13428     8/imm32/value:byte
13429     0/imm32/left:unused
13430     0/imm32/right:null
13431     0/imm32/right:null
13432 
13433 == code
13434 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
13435     # . prologue
13436     55/push-ebp
13437     89/<- %ebp 4/r32/esp
13438     # . save registers
13439     50/push-eax
13440     51/push-ecx
13441     # ecx = primitive
13442     8b/-> *(ebp+0x10) 1/r32/ecx
13443     # emit primitive name
13444     (emit-indent *(ebp+8) *Curr-block-depth)
13445     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
13446     (write-buffered *(ebp+8) %eax)
13447     # emit rm32 if necessary
13448     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
13449     # emit r32 if necessary
13450     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
13451     # emit imm32 if necessary
13452     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
13453     # emit disp32 if necessary
13454     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
13455     (write-buffered *(ebp+8) Newline)
13456 $emit-subx-primitive:end:
13457     # . restore registers
13458     59/pop-to-ecx
13459     58/pop-to-eax
13460     # . epilogue
13461     89/<- %esp 5/r32/ebp
13462     5d/pop-to-ebp
13463     c3/return
13464 
13465 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13466     # . prologue
13467     55/push-ebp
13468     89/<- %ebp 4/r32/esp
13469     # . save registers
13470     50/push-eax
13471     # if (l == 0) return
13472     81 7/subop/compare *(ebp+0xc) 0/imm32
13473     74/jump-if-= $emit-subx-rm32:end/disp8
13474     # var v/eax: (addr stmt-var)
13475     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
13476     (emit-subx-var-as-rm32 *(ebp+8) %eax)
13477 $emit-subx-rm32:end:
13478     # . restore registers
13479     58/pop-to-eax
13480     # . epilogue
13481     89/<- %esp 5/r32/ebp
13482     5d/pop-to-ebp
13483     c3/return
13484 
13485 get-stmt-operand-from-arg-location:  # stmt: (addr stmt), l: arg-location, err: (addr buffered-file), ed: (addr exit-descriptor) -> var/eax: (addr stmt-var)
13486     # . prologue
13487     55/push-ebp
13488     89/<- %ebp 4/r32/esp
13489     # . save registers
13490     51/push-ecx
13491     # eax = l
13492     8b/-> *(ebp+0xc) 0/r32/eax
13493     # ecx = stmt
13494     8b/-> *(ebp+8) 1/r32/ecx
13495     # if (l == 1) return stmt->inouts
13496     {
13497       3d/compare-eax-and 1/imm32
13498       75/jump-if-!= break/disp8
13499 $get-stmt-operand-from-arg-location:1:
13500       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13501       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13502     }
13503     # if (l == 2) return stmt->inouts->next
13504     {
13505       3d/compare-eax-and 2/imm32
13506       75/jump-if-!= break/disp8
13507 $get-stmt-operand-from-arg-location:2:
13508       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13509       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13510       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13511     }
13512     # if (l == 3) return stmt->outputs
13513     {
13514       3d/compare-eax-and 3/imm32
13515       75/jump-if-!= break/disp8
13516 $get-stmt-operand-from-arg-location:3:
13517       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13518       eb/jump $get-stmt-operand-from-arg-location:end/disp8
13519     }
13520     # abort
13521     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
13522 $get-stmt-operand-from-arg-location:end:
13523     # . restore registers
13524     59/pop-to-ecx
13525     # . epilogue
13526     89/<- %esp 5/r32/ebp
13527     5d/pop-to-ebp
13528     c3/return
13529 
13530 $get-stmt-operand-from-arg-location:abort:
13531     # error("invalid arg-location " eax)
13532     (write-buffered *(ebp+0x10) "invalid arg-location ")
13533     (print-int32-buffered *(ebp+0x10) %eax)
13534     (write-buffered *(ebp+0x10) Newline)
13535     (flush *(ebp+0x10))
13536     (stop *(ebp+0x14) 1)
13537     # never gets here
13538 
13539 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13540     # . prologue
13541     55/push-ebp
13542     89/<- %ebp 4/r32/esp
13543     # . save registers
13544     50/push-eax
13545     51/push-ecx
13546     # if (l == 0) return
13547     81 7/subop/compare *(ebp+0xc) 0/imm32
13548     0f 84/jump-if-= $emit-subx-r32:end/disp32
13549     # var v/eax: (addr stmt-var)
13550     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13551     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13552     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13553     (maybe-get Registers %eax 0xc)  # => eax: (addr register-index)
13554     (write-buffered *(ebp+8) Space)
13555     (print-int32-buffered *(ebp+8) *eax)
13556     (write-buffered *(ebp+8) "/r32")
13557 $emit-subx-r32:end:
13558     # . restore registers
13559     59/pop-to-ecx
13560     58/pop-to-eax
13561     # . epilogue
13562     89/<- %esp 5/r32/ebp
13563     5d/pop-to-ebp
13564     c3/return
13565 
13566 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
13567     # . prologue
13568     55/push-ebp
13569     89/<- %ebp 4/r32/esp
13570     # . save registers
13571     50/push-eax
13572     51/push-ecx
13573     # if (l == 0) return
13574     81 7/subop/compare *(ebp+0xc) 0/imm32
13575     0f 84/jump-if-= $emit-subx-imm32:end/disp32
13576     # var v/eax: (handle var)
13577     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
13578     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13579     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13580     (write-buffered *(ebp+8) Space)
13581     (write-buffered *(ebp+8) %eax)
13582     (write-buffered *(ebp+8) "/imm32")
13583 $emit-subx-imm32:end:
13584     # . restore registers
13585     59/pop-to-ecx
13586     58/pop-to-eax
13587     # . epilogue
13588     89/<- %esp 5/r32/ebp
13589     5d/pop-to-ebp
13590     c3/return
13591 
13592 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13593     # . prologue
13594     55/push-ebp
13595     89/<- %ebp 4/r32/esp
13596     # . save registers
13597     50/push-eax
13598     51/push-ecx
13599     # if (location == 0) return
13600     81 7/subop/compare *(ebp+0xc) 0/imm32
13601     0f 84/jump-if-= $emit-subx-disp32:end/disp32
13602     # var v/eax: (addr stmt-var)
13603     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
13604     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13605     (lookup *eax *(eax+4))  # Var-name Var-name => eax
13606     (write-buffered *(ebp+8) Space)
13607     (write-buffered *(ebp+8) %eax)
13608     # hack: if instruction operation starts with "break", emit ":break"
13609     # var name/ecx: (addr array byte) = lookup(stmt->operation)
13610     8b/-> *(ebp+0x10) 0/r32/eax
13611     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
13612     89/<- %ecx 0/r32/eax
13613     {
13614       (string-starts-with? %ecx "break")  # => eax
13615       3d/compare-eax-and 0/imm32/false
13616       74/jump-if-= break/disp8
13617       (write-buffered *(ebp+8) ":break")
13618     }
13619     # hack: if instruction operation starts with "loop", emit ":loop"
13620     {
13621       (string-starts-with? %ecx "loop")  # => eax
13622       3d/compare-eax-and 0/imm32/false
13623       74/jump-if-= break/disp8
13624       (write-buffered *(ebp+8) ":loop")
13625     }
13626     (write-buffered *(ebp+8) "/disp32")
13627 $emit-subx-disp32:end:
13628     # . restore registers
13629     59/pop-to-ecx
13630     58/pop-to-eax
13631     # . epilogue
13632     89/<- %esp 5/r32/ebp
13633     5d/pop-to-ebp
13634     c3/return
13635 
13636 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
13637     # . prologue
13638     55/push-ebp
13639     89/<- %ebp 4/r32/esp
13640     # . save registers
13641     50/push-eax
13642     51/push-ecx
13643     #
13644     (emit-indent *(ebp+8) *Curr-block-depth)
13645     (write-buffered *(ebp+8) "(")
13646     # ecx = stmt
13647     8b/-> *(ebp+0xc) 1/r32/ecx
13648     # - emit function name
13649     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13650     (write-buffered *(ebp+8) %eax)
13651     # - emit arguments
13652     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
13653     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13654     {
13655       # if (curr == null) break
13656       3d/compare-eax-and 0/imm32
13657       74/jump-if-= break/disp8
13658       #
13659       (emit-subx-call-operand *(ebp+8) %eax)
13660       # curr = lookup(curr->next)
13661       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13662       eb/jump loop/disp8
13663     }
13664     #
13665     (write-buffered *(ebp+8) ")\n")
13666 $emit-call:end:
13667     # . restore registers
13668     59/pop-to-ecx
13669     58/pop-to-eax
13670     # . epilogue
13671     89/<- %esp 5/r32/ebp
13672     5d/pop-to-ebp
13673     c3/return
13674 
13675 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
13676     # shares code with emit-subx-var-as-rm32
13677     # . prologue
13678     55/push-ebp
13679     89/<- %ebp 4/r32/esp
13680     # . save registers
13681     50/push-eax
13682     51/push-ecx
13683     56/push-esi
13684     # ecx = s
13685     8b/-> *(ebp+0xc) 1/r32/ecx
13686     # var operand/esi: (addr var) = lookup(s->value)
13687     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13688     89/<- %esi 0/r32/eax
13689     # if (operand->register && !s->is-deref?) emit "%__"
13690     {
13691 $emit-subx-call-operand:check-for-register-direct:
13692       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13693       74/jump-if-= break/disp8
13694       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13695       75/jump-if-!= break/disp8
13696 $emit-subx-call-operand:register-direct:
13697       (write-buffered *(ebp+8) " %")
13698       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13699       (write-buffered *(ebp+8) %eax)
13700       e9/jump $emit-subx-call-operand:end/disp32
13701     }
13702     # else if (operand->register && s->is-deref?) emit "*__"
13703     {
13704 $emit-subx-call-operand:check-for-register-indirect:
13705       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13706       74/jump-if-= break/disp8
13707       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13708       74/jump-if-= break/disp8
13709 $emit-subx-call-operand:register-indirect:
13710       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
13711       e9/jump $emit-subx-call-operand:end/disp32
13712     }
13713     # else if (operand->stack-offset) emit "*(ebp+__)"
13714     {
13715       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
13716       74/jump-if-= break/disp8
13717 $emit-subx-call-operand:stack:
13718       (emit-subx-call-operand-stack *(ebp+8) %esi)
13719       e9/jump $emit-subx-call-operand:end/disp32
13720     }
13721     # else if (operand->type == literal) emit "__"
13722     {
13723       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
13724       81 7/subop/compare *(eax+4) 0/imm32  # Tree-left
13725       75/jump-if-!= break/disp8
13726 $emit-subx-call-operand:literal:
13727       (write-buffered *(ebp+8) Space)
13728       (lookup *esi *(esi+4))  # Var-name Var-name => eax
13729       (write-buffered *(ebp+8) %eax)
13730     }
13731 $emit-subx-call-operand:end:
13732     # . restore registers
13733     5e/pop-to-esi
13734     59/pop-to-ecx
13735     58/pop-to-eax
13736     # . epilogue
13737     89/<- %esp 5/r32/ebp
13738     5d/pop-to-ebp
13739     c3/return
13740 
13741 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
13742     # . prologue
13743     55/push-ebp
13744     89/<- %ebp 4/r32/esp
13745     # . save registers
13746     50/push-eax
13747     51/push-ecx
13748     56/push-esi
13749     # esi = v
13750     8b/-> *(ebp+0xc) 6/r32/esi
13751     # var size/ecx: int = size-of-deref(v)
13752     (size-of-deref %esi)  # => eax
13753     89/<- %ecx 0/r32/eax
13754     # var reg-name/esi: (addr array byte) = lookup(v->register)
13755     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13756     89/<- %esi 0/r32/eax
13757     # TODO: assert size is a multiple of 4
13758     # var i/eax: int = 0
13759     b8/copy-to-eax 0/imm32
13760     {
13761 $emit-subx-call-operand-register-indirect:loop:
13762       # if (i >= size) break
13763       39/compare %eax 1/r32/ecx
13764       7d/jump-if->= break/disp8
13765       # emit " *(" v->register "+" i ")"
13766       (write-buffered *(ebp+8) " *(")
13767       (write-buffered *(ebp+8) %esi)
13768       (write-buffered *(ebp+8) "+")
13769       (print-int32-buffered *(ebp+8) %eax)
13770       (write-buffered *(ebp+8) ")")
13771       # i += 4
13772       05/add-to-eax 4/imm32
13773       #
13774       eb/jump loop/disp8
13775     }
13776 $emit-subx-call-operand-register-indirect:end:
13777     # . restore registers
13778     5e/pop-to-esi
13779     59/pop-to-ecx
13780     58/pop-to-eax
13781     # . epilogue
13782     89/<- %esp 5/r32/ebp
13783     5d/pop-to-ebp
13784     c3/return
13785 
13786 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
13787     # . prologue
13788     55/push-ebp
13789     89/<- %ebp 4/r32/esp
13790     # . save registers
13791     50/push-eax
13792     51/push-ecx
13793     56/push-esi
13794     # esi = v
13795     8b/-> *(ebp+0xc) 6/r32/esi
13796     # var curr/ecx: int = v->offset
13797     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
13798     # var max/eax: int = v->offset + size-of(v)
13799     (size-of %esi)  # => eax
13800     # TODO: assert size is a multiple of 4
13801     01/add-to %eax 1/r32/ecx
13802     {
13803 $emit-subx-call-operand-stack:loop:
13804       # if (curr >= max) break
13805       39/compare %ecx 0/r32/eax
13806       7d/jump-if->= break/disp8
13807       # emit " *(ebp+" curr ")"
13808       (write-buffered *(ebp+8) " *(ebp+")
13809       (print-int32-buffered *(ebp+8) %ecx)
13810       (write-buffered *(ebp+8) ")")
13811       # i += 4
13812       81 0/subop/add %ecx 4/imm32
13813       #
13814       eb/jump loop/disp8
13815     }
13816 $emit-subx-call-operand-stack:end:
13817     # . restore registers
13818     5e/pop-to-esi
13819     59/pop-to-ecx
13820     58/pop-to-eax
13821     # . epilogue
13822     89/<- %esp 5/r32/ebp
13823     5d/pop-to-ebp
13824     c3/return
13825 
13826 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
13827     # . prologue
13828     55/push-ebp
13829     89/<- %ebp 4/r32/esp
13830     # . save registers
13831     50/push-eax
13832     51/push-ecx
13833     56/push-esi
13834     # ecx = s
13835     8b/-> *(ebp+0xc) 1/r32/ecx
13836     # var operand/esi: (addr var) = lookup(s->value)
13837     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13838     89/<- %esi 0/r32/eax
13839     # if (operand->register && s->is-deref?) emit "*__"
13840     {
13841 $emit-subx-var-as-rm32:check-for-register-indirect:
13842       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13843       74/jump-if-= break/disp8
13844       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13845       74/jump-if-= break/disp8
13846 $emit-subx-var-as-rm32:register-indirect:
13847       (write-buffered *(ebp+8) " *")
13848       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13849       (write-buffered *(ebp+8) %eax)
13850       e9/jump $emit-subx-var-as-rm32:end/disp32
13851     }
13852     # if (operand->register && !s->is-deref?) emit "%__"
13853     {
13854 $emit-subx-var-as-rm32:check-for-register-direct:
13855       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
13856       74/jump-if-= break/disp8
13857       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13858       75/jump-if-!= break/disp8
13859 $emit-subx-var-as-rm32:register-direct:
13860       (write-buffered *(ebp+8) " %")
13861       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
13862       (write-buffered *(ebp+8) %eax)
13863       e9/jump $emit-subx-var-as-rm32:end/disp32
13864     }
13865     # else if (operand->stack-offset) emit "*(ebp+__)"
13866     {
13867       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
13868       74/jump-if-= break/disp8
13869 $emit-subx-var-as-rm32:stack:
13870       (write-buffered *(ebp+8) Space)
13871       (write-buffered *(ebp+8) "*(ebp+")
13872       (print-int32-buffered *(ebp+8) *(esi+0x14))  # Var-offset
13873       (write-buffered *(ebp+8) ")")
13874     }
13875 $emit-subx-var-as-rm32:end:
13876     # . restore registers
13877     5e/pop-to-esi
13878     59/pop-to-ecx
13879     58/pop-to-eax
13880     # . epilogue
13881     89/<- %esp 5/r32/ebp
13882     5d/pop-to-ebp
13883     c3/return
13884 
13885 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
13886     # . prologue
13887     55/push-ebp
13888     89/<- %ebp 4/r32/esp
13889     # . save registers
13890     51/push-ecx
13891     # var curr/ecx: (addr primitive) = primitives
13892     8b/-> *(ebp+8) 1/r32/ecx
13893     {
13894 $find-matching-primitive:loop:
13895       # if (curr == null) break
13896       81 7/subop/compare %ecx 0/imm32
13897       0f 84/jump-if-= break/disp32
13898       # if match(curr, stmt) return curr
13899       {
13900         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
13901         3d/compare-eax-and 0/imm32/false
13902         74/jump-if-= break/disp8
13903         89/<- %eax 1/r32/ecx
13904         eb/jump $find-matching-primitive:end/disp8
13905       }
13906 $find-matching-primitive:next-primitive:
13907       # curr = curr->next
13908       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
13909       89/<- %ecx 0/r32/eax
13910       #
13911       e9/jump loop/disp32
13912     }
13913     # return null
13914     b8/copy-to-eax 0/imm32
13915 $find-matching-primitive:end:
13916     # . restore registers
13917     59/pop-to-ecx
13918     # . epilogue
13919     89/<- %esp 5/r32/ebp
13920     5d/pop-to-ebp
13921     c3/return
13922 
13923 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
13924     # A mu stmt matches a primitive if the name matches, all the inout vars
13925     # match, and all the output vars match.
13926     # Vars match if types match and registers match.
13927     # In addition, a stmt output matches a primitive's output if types match
13928     # and the primitive has a wildcard register.
13929     # . prologue
13930     55/push-ebp
13931     89/<- %ebp 4/r32/esp
13932     # . save registers
13933     51/push-ecx
13934     52/push-edx
13935     53/push-ebx
13936     56/push-esi
13937     57/push-edi
13938     # ecx = stmt
13939     8b/-> *(ebp+8) 1/r32/ecx
13940     # edx = primitive
13941     8b/-> *(ebp+0xc) 2/r32/edx
13942     {
13943 $mu-stmt-matches-primitive?:check-name:
13944       # if (primitive->name != stmt->operation) return false
13945       # . var esi: (addr array byte) = lookup(stmt->operation)
13946       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13947       89/<- %esi 0/r32/eax
13948       # . var edi: (addr array byte) = lookup(primitive->name)
13949       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
13950       89/<- %edi 0/r32/eax
13951       (string-equal? %esi %edi)  # => eax
13952       3d/compare-eax-and 0/imm32/false
13953       75/jump-if-!= break/disp8
13954       b8/copy-to-eax 0/imm32
13955       e9/jump $mu-stmt-matches-primitive?:end/disp32
13956     }
13957     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
13958     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13959     89/<- %esi 0/r32/eax
13960     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
13961     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
13962     89/<- %edi 0/r32/eax
13963     {
13964 $mu-stmt-matches-primitive?:inouts-loop:
13965       # if (curr == 0 && curr2 == 0) move on to check outputs
13966       {
13967 $mu-stmt-matches-primitive?:check-both-inouts-null:
13968         81 7/subop/compare %esi 0/imm32
13969         75/jump-if-!= break/disp8
13970 $mu-stmt-matches-primitive?:stmt-inout-null:
13971         81 7/subop/compare %edi 0/imm32
13972         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
13973 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
13974         # return false
13975         b8/copy-to-eax 0/imm32/false
13976         e9/jump $mu-stmt-matches-primitive?:end/disp32
13977       }
13978       # if (curr2 == 0) return false
13979       {
13980 $mu-stmt-matches-primitive?:check-prim-inout-null:
13981         81 7/subop/compare %edi 0/imm32
13982         75/jump-if-!= break/disp8
13983 $mu-stmt-matches-primitive?:prim-inout-null:
13984         b8/copy-to-eax 0/imm32/false
13985         e9/jump $mu-stmt-matches-primitive?:end/disp32
13986       }
13987       # if (curr != curr2) return false
13988       {
13989 $mu-stmt-matches-primitive?:check-inouts-match:
13990         (lookup *edi *(edi+4))  # List-value List-value => eax
13991         (operand-matches-primitive? %esi %eax)  # => eax
13992         3d/compare-eax-and 0/imm32/false
13993         75/jump-if-!= break/disp8
13994 $mu-stmt-matches-primitive?:inouts-match:
13995         b8/copy-to-eax 0/imm32/false
13996         e9/jump $mu-stmt-matches-primitive?:end/disp32
13997       }
13998 $mu-stmt-matches-primitive?:next-inout:
13999       # curr = lookup(curr->next)
14000       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
14001       89/<- %esi 0/r32/eax
14002       # curr2 = lookup(curr2->next)
14003       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
14004       89/<- %edi 0/r32/eax
14005       #
14006       e9/jump loop/disp32
14007     }
14008 $mu-stmt-matches-primitive?:check-outputs:
14009     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
14010     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14011     89/<- %esi 0/r32/eax
14012     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
14013     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
14014     89/<- %edi 0/r32/eax
14015     {
14016 $mu-stmt-matches-primitive?:outputs-loop:
14017       # if (curr == 0) return (curr2 == 0)
14018       {
14019 $mu-stmt-matches-primitive?:check-both-outputs-null:
14020         81 7/subop/compare %esi 0/imm32
14021         75/jump-if-!= break/disp8
14022         {
14023 $mu-stmt-matches-primitive?:stmt-output-null:
14024           81 7/subop/compare %edi 0/imm32
14025           75/jump-if-!= break/disp8
14026 $mu-stmt-matches-primitive?:both-outputs-null:
14027           # return true
14028           b8/copy-to-eax 1/imm32
14029           e9/jump $mu-stmt-matches-primitive?:end/disp32
14030         }
14031 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
14032         # return false
14033         b8/copy-to-eax 0/imm32
14034         e9/jump $mu-stmt-matches-primitive?:end/disp32
14035       }
14036       # if (curr2 == 0) return false
14037       {
14038 $mu-stmt-matches-primitive?:check-prim-output-null:
14039         81 7/subop/compare %edi 0/imm32
14040         75/jump-if-!= break/disp8
14041 $mu-stmt-matches-primitive?:prim-output-is-null:
14042         b8/copy-to-eax 0/imm32
14043         e9/jump $mu-stmt-matches-primitive?:end/disp32
14044       }
14045       # if (curr != curr2) return false
14046       {
14047 $mu-stmt-matches-primitive?:check-outputs-match:
14048         (lookup *edi *(edi+4))  # List-value List-value => eax
14049         (operand-matches-primitive? %esi %eax)  # => eax
14050         3d/compare-eax-and 0/imm32/false
14051         75/jump-if-!= break/disp8
14052 $mu-stmt-matches-primitive?:outputs-match:
14053         b8/copy-to-eax 0/imm32
14054         e9/jump $mu-stmt-matches-primitive?:end/disp32
14055       }
14056 $mu-stmt-matches-primitive?:next-output:
14057       # curr = lookup(curr->next)
14058       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
14059       89/<- %esi 0/r32/eax
14060       # curr2 = lookup(curr2->next)
14061       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
14062       89/<- %edi 0/r32/eax
14063       #
14064       e9/jump loop/disp32
14065     }
14066 $mu-stmt-matches-primitive?:return-true:
14067     b8/copy-to-eax 1/imm32
14068 $mu-stmt-matches-primitive?:end:
14069     # . restore registers
14070     5f/pop-to-edi
14071     5e/pop-to-esi
14072     5b/pop-to-ebx
14073     5a/pop-to-edx
14074     59/pop-to-ecx
14075     # . epilogue
14076     89/<- %esp 5/r32/ebp
14077     5d/pop-to-ebp
14078     c3/return
14079 
14080 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
14081     # . prologue
14082     55/push-ebp
14083     89/<- %ebp 4/r32/esp
14084     # . save registers
14085     51/push-ecx
14086     52/push-edx
14087     53/push-ebx
14088     56/push-esi
14089     57/push-edi
14090     # ecx = s
14091     8b/-> *(ebp+8) 1/r32/ecx
14092     # var var/esi: (addr var) = lookup(s->value)
14093     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
14094     89/<- %esi 0/r32/eax
14095     # edi = prim-var
14096     8b/-> *(ebp+0xc) 7/r32/edi
14097 $operand-matches-primitive?:check-type:
14098     # if (var->type != prim-var->type) return false
14099     # . var vtype/ebx: (addr tree type-id) = lookup(var->type)
14100     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
14101     89/<- %ebx 0/r32/eax
14102     # . var ptype/eax: (addr tree type-id) = lookup(prim-var->type)
14103     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
14104     (subx-type-equal? %ebx %eax)  # => eax
14105     3d/compare-eax-and 0/imm32/false
14106     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
14107     {
14108 $operand-matches-primitive?:check-register:
14109       # if prim-var is in memory and var is in register but dereference, match
14110       {
14111         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
14112         0f 85/jump-if-!= break/disp32
14113         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
14114         74/jump-if-= break/disp8
14115         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14116         74/jump-if-= break/disp8
14117 $operand-matches-primitive?:var-deref-match:
14118         e9/jump $operand-matches-primitive?:return-true/disp32
14119       }
14120       # if prim-var is in register and var is in register but dereference, no match
14121       {
14122         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
14123         0f 84/jump-if-= break/disp32
14124         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
14125         0f 84/jump-if-= break/disp32
14126         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
14127         74/jump-if-= break/disp8
14128 $operand-matches-primitive?:var-deref-no-match:
14129         e9/jump $operand-matches-primitive?:return-false/disp32
14130       }
14131       # return false if var->register doesn't match prim-var->register
14132       {
14133         # if register addresses are equal, it's a match
14134         # var vreg/ebx: (addr array byte) = lookup(var->register)
14135         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
14136         89/<- %ebx 0/r32/eax
14137         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
14138         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
14139         89/<- %ecx 0/r32/eax
14140         # if (vreg == preg) break
14141         39/compare %ecx 3/r32/ebx
14142         74/jump-if-= break/disp8
14143 $operand-matches-primitive?:var-register-no-match:
14144         # if either address is 0, return false
14145         81 7/subop/compare %ebx 0/imm32
14146         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
14147         81 7/subop/compare %ecx 0/imm32
14148         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
14149         # if prim-var->register is wildcard, it's a match
14150         (string-equal? %ecx "*")  # Any-register => eax
14151         3d/compare-eax-and 0/imm32/false
14152         75/jump-if-!= break/disp8
14153 $operand-matches-primitive?:wildcard-no-match:
14154         # if string contents aren't equal, return false
14155         (string-equal? %ecx %ebx)  # => eax
14156         3d/compare-eax-and 0/imm32/false
14157         74/jump-if-= $operand-matches-primitive?:return-false/disp8
14158       }
14159     }
14160 $operand-matches-primitive?:return-true:
14161     b8/copy-to-eax 1/imm32/true
14162     eb/jump $operand-matches-primitive?:end/disp8
14163 $operand-matches-primitive?:return-false:
14164     b8/copy-to-eax 0/imm32/false
14165 $operand-matches-primitive?:end:
14166     # . restore registers
14167     5f/pop-to-edi
14168     5e/pop-to-esi
14169     5b/pop-to-ebx
14170     5a/pop-to-edx
14171     59/pop-to-ecx
14172     # . epilogue
14173     89/<- %esp 5/r32/ebp
14174     5d/pop-to-ebp
14175     c3/return
14176 
14177 subx-type-equal?:  # a: (addr tree type-id), b: (addr tree type-id) -> result/eax: boolean
14178     # . prologue
14179     55/push-ebp
14180     89/<- %ebp 4/r32/esp
14181     # . save registers
14182     51/push-ecx
14183     # var alit/ecx: boolean = is-literal-type?(a)
14184     (is-simple-mu-type? *(ebp+8) 0)  # => eax
14185     89/<- %ecx 0/r32/eax
14186     # var blit/eax: boolean = is-literal-type?(b)
14187     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
14188     # return alit == blit
14189     39/compare %eax 1/r32/ecx
14190     0f 94/set-byte-if-= %al
14191     81 4/subop/and %eax 0xff/imm32
14192 $subx-type-equal?:end:
14193     # . restore registers
14194     59/pop-to-ecx
14195     # . epilogue
14196     89/<- %esp 5/r32/ebp
14197     5d/pop-to-ebp
14198     c3/return
14199 
14200 is-simple-mu-type?:  # a: (addr tree type-id), n: type-id -> result/eax: boolean
14201     # . prologue
14202     55/push-ebp
14203     89/<- %ebp 4/r32/esp
14204     # . save registers
14205     51/push-ecx
14206     # ecx = n
14207     8b/-> *(ebp+0xc) 1/r32/ecx
14208     # return (a->value == n)
14209     8b/-> *(ebp+8) 0/r32/eax
14210     39/compare *(eax+4) 1/r32/ecx  # Tree-value
14211     0f 94/set-byte-if-= %al
14212     81 4/subop/and %eax 0xff/imm32
14213 $is-simple-mu-type?:end:
14214     # . restore registers
14215     59/pop-to-ecx
14216     # . epilogue
14217     89/<- %esp 5/r32/ebp
14218     5d/pop-to-ebp
14219     c3/return
14220 
14221 test-emit-subx-stmt-primitive:
14222     # Primitive operation on a variable on the stack.
14223     #   increment foo
14224     # =>
14225     #   ff 0/subop/increment *(ebp-8)
14226     #
14227     # There's a variable on the var stack as follows:
14228     #   name: 'foo'
14229     #   type: int
14230     #   stack-offset: -8
14231     #
14232     # There's a primitive with this info:
14233     #   name: 'increment'
14234     #   inouts: int/mem
14235     #   value: 'ff 0/subop/increment'
14236     #
14237     # . prologue
14238     55/push-ebp
14239     89/<- %ebp 4/r32/esp
14240     # setup
14241     (clear-stream _test-output-stream)
14242     (clear-stream $_test-output-buffered-file->buffer)
14243     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
14244 $test-emit-subx-stmt-primitive:initialize-type:
14245     # var type/ecx: (payload tree type-id) = int
14246     68/push 0/imm32/right:null
14247     68/push 0/imm32/right:null
14248     68/push 0/imm32/left:unused
14249     68/push 1/imm32/value:int
14250     68/push 1/imm32/is-atom?:true
14251     68/push 0x11/imm32/alloc-id:fake:payload
14252     89/<- %ecx 4/r32/esp
14253 $test-emit-subx-stmt-primitive:initialize-var:
14254     # var var-foo/ecx: (payload var) = var(type)
14255     68/push 0/imm32/no-register
14256     68/push 0/imm32/no-register
14257     68/push -8/imm32/stack-offset
14258     68/push 1/imm32/block-depth
14259     51/push-ecx/type
14260     68/push 0x11/imm32/alloc-id:fake
14261     68/push 0/imm32/name
14262     68/push 0/imm32/name
14263     68/push 0x11/imm32/alloc-id:fake:payload
14264     89/<- %ecx 4/r32/esp
14265 $test-emit-subx-stmt-primitive:initialize-var-name:
14266     # var-foo->name = "foo"
14267     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14268     (copy-array Heap "foo" %eax)
14269 $test-emit-subx-stmt-primitive:initialize-stmt-var:
14270     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
14271     68/push 0/imm32/is-deref:false
14272     68/push 0/imm32/next
14273     68/push 0/imm32/next
14274     51/push-ecx/var-foo
14275     68/push 0x11/imm32/alloc-id:fake
14276     68/push 0x11/imm32/alloc-id:fake:payload
14277     89/<- %ebx 4/r32/esp
14278 $test-emit-subx-stmt-primitive:initialize-stmt:
14279     # var stmt/esi: (addr statement)
14280     68/push 0/imm32/no-outputs
14281     68/push 0/imm32/no-outputs
14282     53/push-ebx/inouts
14283     68/push 0x11/imm32/alloc-id:fake
14284     68/push 0/imm32/operation
14285     68/push 0/imm32/operation
14286     68/push 1/imm32/tag
14287     89/<- %esi 4/r32/esp
14288 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
14289     # stmt->operation = "increment"
14290     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14291     (copy-array Heap "increment" %eax)
14292 $test-emit-subx-stmt-primitive:initialize-primitive:
14293     # var primitives/ebx: (addr primitive)
14294     68/push 0/imm32/next
14295     68/push 0/imm32/next
14296     68/push 0/imm32/output-is-write-only
14297     68/push 0/imm32/no-disp32
14298     68/push 0/imm32/no-imm32
14299     68/push 0/imm32/no-r32
14300     68/push 1/imm32/rm32-is-first-inout
14301     68/push 0/imm32/subx-name
14302     68/push 0/imm32/subx-name
14303     68/push 0/imm32/no-outputs
14304     68/push 0/imm32/no-outputs
14305     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14306     68/push 0x11/imm32/alloc-id:fake
14307     68/push 0/imm32/name
14308     68/push 0/imm32/name
14309     89/<- %ebx 4/r32/esp
14310 $test-emit-subx-stmt-primitive:initialize-primitive-name:
14311     # primitives->name = "increment"
14312     (copy-array Heap "increment" %ebx)  # Primitive-name
14313 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
14314     # primitives->subx-name = "ff 0/subop/increment"
14315     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14316     (copy-array Heap "ff 0/subop/increment" %eax)
14317     # convert
14318     c7 0/subop/copy *Curr-block-depth 0/imm32
14319     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
14320     (flush _test-output-buffered-file)
14321 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14327     # check output
14328     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
14329     # . epilogue
14330     89/<- %esp 5/r32/ebp
14331     5d/pop-to-ebp
14332     c3/return
14333 
14334 test-emit-subx-stmt-primitive-register:
14335     # Primitive operation on a variable in a register.
14336     #   foo <- increment
14337     # =>
14338     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14339     #
14340     # There's a variable on the var stack as follows:
14341     #   name: 'foo'
14342     #   type: int
14343     #   register: 'eax'
14344     #
14345     # There's a primitive with this info:
14346     #   name: 'increment'
14347     #   out: int/reg
14348     #   value: 'ff 0/subop/increment'
14349     #
14350     # . prologue
14351     55/push-ebp
14352     89/<- %ebp 4/r32/esp
14353     # setup
14354     (clear-stream _test-output-stream)
14355     (clear-stream $_test-output-buffered-file->buffer)
14356 $test-emit-subx-stmt-primitive-register:initialize-type:
14357     # var type/ecx: (payload tree type-id) = int
14358     68/push 0/imm32/right:null
14359     68/push 0/imm32/right:null
14360     68/push 0/imm32/left:unused
14361     68/push 1/imm32/value:int
14362     68/push 1/imm32/is-atom?:true
14363     68/push 0x11/imm32/alloc-id:fake:payload
14364     89/<- %ecx 4/r32/esp
14365 $test-emit-subx-stmt-primitive-register:initialize-var:
14366     # var var-foo/ecx: (payload var)
14367     68/push 0/imm32/register
14368     68/push 0/imm32/register
14369     68/push 0/imm32/no-stack-offset
14370     68/push 1/imm32/block-depth
14371     51/push-ecx
14372     68/push 0x11/imm32/alloc-id:fake
14373     68/push 0/imm32/name
14374     68/push 0/imm32/name
14375     68/push 0x11/imm32/alloc-id:fake:payload
14376     89/<- %ecx 4/r32/esp
14377 $test-emit-subx-stmt-primitive-register:initialize-var-name:
14378     # var-foo->name = "foo"
14379     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14380     (copy-array Heap "foo" %eax)
14381 $test-emit-subx-stmt-primitive-register:initialize-var-register:
14382     # var-foo->register = "eax"
14383     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14384     (copy-array Heap "eax" %eax)
14385 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
14386     # var operand/ebx: (payload stmt-var)
14387     68/push 0/imm32/is-deref:false
14388     68/push 0/imm32/next
14389     68/push 0/imm32/next
14390     51/push-ecx/var-foo
14391     68/push 0x11/imm32/alloc-id:fake
14392     68/push 0x11/imm32/alloc-id:fake:payload
14393     89/<- %ebx 4/r32/esp
14394 $test-emit-subx-stmt-primitive-register:initialize-stmt:
14395     # var stmt/esi: (addr statement)
14396     53/push-ebx/outputs
14397     68/push 0x11/imm32/alloc-id:fake
14398     68/push 0/imm32/no-inouts
14399     68/push 0/imm32/no-inouts
14400     68/push 0/imm32/operation
14401     68/push 0/imm32/operation
14402     68/push 1/imm32
14403     89/<- %esi 4/r32/esp
14404 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
14405     # stmt->operation = "increment"
14406     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14407     (copy-array Heap "increment" %eax)
14408 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
14409     # var formal-var/ebx: (payload var)
14410     68/push 0/imm32/register
14411     68/push 0/imm32/register
14412     68/push 0/imm32/no-stack-offset
14413     68/push 1/imm32/block-depth
14414     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14415     68/push 0x11/imm32/alloc-id:fake
14416     68/push 0/imm32/name
14417     68/push 0/imm32/name
14418     68/push 0x11/imm32/alloc-id:fake:payload
14419     89/<- %ebx 4/r32/esp
14420 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
14421     # formal-var->name = "dummy"
14422     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14423     (copy-array Heap "dummy" %eax)
14424 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
14425     # formal-var->register = "*"
14426     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14427     (copy-array Heap "*" %eax)  # Any-register
14428 $test-emit-subx-stmt-primitive-register:initialize-var-list:
14429     # var formal-outputs/ebx: (payload list var)
14430     68/push 0/imm32/next
14431     68/push 0/imm32/next
14432     53/push-ebx/formal-var
14433     68/push 0x11/imm32/alloc-id:fake
14434     68/push 0x11/imm32/alloc-id:fake:payload
14435     89/<- %ebx 4/r32/esp
14436 $test-emit-subx-stmt-primitive-register:initialize-primitive:
14437     # var primitives/ebx: (addr primitive)
14438     68/push 0/imm32/next
14439     68/push 0/imm32/next
14440     68/push 0/imm32/output-is-write-only
14441     68/push 0/imm32/no-disp32
14442     68/push 0/imm32/no-imm32
14443     68/push 0/imm32/no-r32
14444     68/push 3/imm32/rm32-is-first-output
14445     68/push 0/imm32/subx-name
14446     68/push 0/imm32/subx-name
14447     53/push-ebx/outputs
14448     68/push 0x11/imm32/alloc-id:fake
14449     68/push 0/imm32/no-inouts
14450     68/push 0/imm32/no-inouts
14451     68/push 0/imm32/name
14452     68/push 0/imm32/name
14453     89/<- %ebx 4/r32/esp
14454 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
14455     # primitives->name = "increment"
14456     (copy-array Heap "increment" %ebx)  # Primitive-name
14457 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
14458     # primitives->subx-name = "ff 0/subop/increment"
14459     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14460     (copy-array Heap "ff 0/subop/increment" %eax)
14461     # convert
14462     c7 0/subop/copy *Curr-block-depth 0/imm32
14463     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
14464     (flush _test-output-buffered-file)
14465 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14471     # check output
14472     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
14473     # . epilogue
14474     89/<- %esp 5/r32/ebp
14475     5d/pop-to-ebp
14476     c3/return
14477 
14478 test-emit-subx-stmt-select-primitive:
14479     # Select the right primitive between overloads.
14480     #   foo <- increment
14481     # =>
14482     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14483     #
14484     # There's a variable on the var stack as follows:
14485     #   name: 'foo'
14486     #   type: int
14487     #   register: 'eax'
14488     #
14489     # There's two primitives, as follows:
14490     #   - name: 'increment'
14491     #     out: int/reg
14492     #     value: 'ff 0/subop/increment'
14493     #   - name: 'increment'
14494     #     inout: int/mem
14495     #     value: 'ff 0/subop/increment'
14496     #
14497     # . prologue
14498     55/push-ebp
14499     89/<- %ebp 4/r32/esp
14500     # setup
14501     (clear-stream _test-output-stream)
14502     (clear-stream $_test-output-buffered-file->buffer)
14503 $test-emit-subx-stmt-select-primitive:initialize-type:
14504     # var type/ecx: (payload tree type-id) = int
14505     68/push 0/imm32/right:null
14506     68/push 0/imm32/right:null
14507     68/push 0/imm32/left:unused
14508     68/push 1/imm32/value:int
14509     68/push 1/imm32/is-atom?:true
14510     68/push 0x11/imm32/alloc-id:fake:payload
14511     89/<- %ecx 4/r32/esp
14512 $test-emit-subx-stmt-select-primitive:initialize-var:
14513     # var var-foo/ecx: (payload var)
14514     68/push 0/imm32/register
14515     68/push 0/imm32/register
14516     68/push 0/imm32/no-stack-offset
14517     68/push 1/imm32/block-depth
14518     51/push-ecx
14519     68/push 0x11/imm32/alloc-id:fake
14520     68/push 0/imm32/name
14521     68/push 0/imm32/name
14522     68/push 0x11/imm32/alloc-id:fake:payload
14523     89/<- %ecx 4/r32/esp
14524 $test-emit-subx-stmt-select-primitive:initialize-var-name:
14525     # var-foo->name = "foo"
14526     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14527     (copy-array Heap "foo" %eax)
14528 $test-emit-subx-stmt-select-primitive:initialize-var-register:
14529     # var-foo->register = "eax"
14530     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14531     (copy-array Heap "eax" %eax)
14532 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
14533     # var operand/ebx: (payload stmt-var)
14534     68/push 0/imm32/is-deref:false
14535     68/push 0/imm32/next
14536     68/push 0/imm32/next
14537     51/push-ecx/var-foo
14538     68/push 0x11/imm32/alloc-id:fake
14539     68/push 0x11/imm32/alloc-id:fake:payload
14540     89/<- %ebx 4/r32/esp
14541 $test-emit-subx-stmt-select-primitive:initialize-stmt:
14542     # var stmt/esi: (addr statement)
14543     53/push-ebx/outputs
14544     68/push 0x11/imm32/alloc-id:fake
14545     68/push 0/imm32/no-inouts
14546     68/push 0/imm32/no-inouts
14547     68/push 0/imm32/operation
14548     68/push 0/imm32/operation
14549     68/push 1/imm32
14550     89/<- %esi 4/r32/esp
14551 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
14552     # stmt->operation = "increment"
14553     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14554     (copy-array Heap "increment" %eax)
14555 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
14556     # var formal-var/ebx: (payload var)
14557     68/push 0/imm32/register
14558     68/push 0/imm32/register
14559     68/push 0/imm32/no-stack-offset
14560     68/push 1/imm32/block-depth
14561     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14562     68/push 0x11/imm32/alloc-id:fake
14563     68/push 0/imm32/name
14564     68/push 0/imm32/name
14565     68/push 0x11/imm32/alloc-id:fake:payload
14566     89/<- %ebx 4/r32/esp
14567 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
14568     # formal-var->name = "dummy"
14569     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14570     (copy-array Heap "dummy" %eax)
14571 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
14572     # formal-var->register = "*"
14573     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14574     (copy-array Heap "*" %eax)  # Any-register
14575 $test-emit-subx-stmt-select-primitive:initialize-var-list:
14576     # var formal-outputs/ebx: (payload list var)
14577     68/push 0/imm32/next
14578     68/push 0/imm32/next
14579     53/push-ebx/formal-var
14580     68/push 0x11/imm32/alloc-id:fake
14581     68/push 0x11/imm32/alloc-id:fake:payload
14582     89/<- %ebx 4/r32/esp
14583 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
14584     # var primitive2/edi: (payload primitive)
14585     68/push 0/imm32/next
14586     68/push 0/imm32/next
14587     68/push 0/imm32/output-is-write-only
14588     68/push 0/imm32/no-disp32
14589     68/push 0/imm32/no-imm32
14590     68/push 0/imm32/no-r32
14591     68/push 3/imm32/rm32-is-first-output
14592     68/push 0/imm32/subx-name
14593     68/push 0/imm32/subx-name
14594     53/push-ebx/outputs
14595     68/push 0x11/imm32/alloc-id:fake
14596     68/push 0/imm32/no-inouts
14597     68/push 0/imm32/no-inouts
14598     68/push 0/imm32/name
14599     68/push 0/imm32/name
14600     68/push 0x11/imm32/alloc-id:fake:payload
14601     89/<- %edi 4/r32/esp
14602 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
14603     # primitives->name = "increment"
14604     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
14605     (copy-array Heap "increment" %eax)
14606 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
14607     # primitives->subx-name = "ff 0/subop/increment"
14608     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
14609     (copy-array Heap "ff 0/subop/increment" %eax)
14610 $test-emit-subx-stmt-select-primitive:initialize-primitive:
14611     # var primitives/ebx: (addr primitive)
14612     57/push-edi
14613     68/push 0x11/imm32/alloc-id:fake
14614     68/push 0/imm32/output-is-write-only
14615     68/push 0/imm32/no-disp32
14616     68/push 0/imm32/no-imm32
14617     68/push 0/imm32/no-r32
14618     68/push 1/imm32/rm32-is-first-inout
14619     68/push 0/imm32/subx-name
14620     68/push 0/imm32/subx-name
14621     68/push 0/imm32/no-outputs
14622     68/push 0/imm32/no-outputs
14623     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14624     68/push 0x11/imm32/alloc-id:fake
14625     68/push 0/imm32/name
14626     68/push 0/imm32/name
14627     89/<- %ebx 4/r32/esp
14628 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
14629     # primitives->name = "increment"
14630     (copy-array Heap "increment" %ebx)  # Primitive-name
14631 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
14632     # primitives->subx-name = "ff 0/subop/increment"
14633     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14634     (copy-array Heap "ff 0/subop/increment" %eax)
14635     # convert
14636     c7 0/subop/copy *Curr-block-depth 0/imm32
14637     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
14638     (flush _test-output-buffered-file)
14639 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14645     # check output
14646     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
14647     # . epilogue
14648     89/<- %esp 5/r32/ebp
14649     5d/pop-to-ebp
14650     c3/return
14651 
14652 test-emit-subx-stmt-select-primitive-2:
14653     # Select the right primitive between overloads.
14654     #   increment foo
14655     # =>
14656     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
14657     #
14658     # There's a variable on the var stack as follows:
14659     #   name: 'foo'
14660     #   type: int
14661     #   register: 'eax'
14662     #
14663     # There's two primitives, as follows:
14664     #   - name: 'increment'
14665     #     out: int/reg
14666     #     value: 'ff 0/subop/increment'
14667     #   - name: 'increment'
14668     #     inout: int/mem
14669     #     value: 'ff 0/subop/increment'
14670     #
14671     # . prologue
14672     55/push-ebp
14673     89/<- %ebp 4/r32/esp
14674     # setup
14675     (clear-stream _test-output-stream)
14676     (clear-stream $_test-output-buffered-file->buffer)
14677 $test-emit-subx-stmt-select-primitive-2:initialize-type:
14678     # var type/ecx: (payload tree type-id) = int
14679     68/push 0/imm32/right:null
14680     68/push 0/imm32/right:null
14681     68/push 0/imm32/left:unused
14682     68/push 1/imm32/value:int
14683     68/push 1/imm32/is-atom?:true
14684     68/push 0x11/imm32/alloc-id:fake:payload
14685     89/<- %ecx 4/r32/esp
14686 $test-emit-subx-stmt-select-primitive-2:initialize-var:
14687     # var var-foo/ecx: (payload var)
14688     68/push 0/imm32/register
14689     68/push 0/imm32/register
14690     68/push 0/imm32/no-stack-offset
14691     68/push 1/imm32/block-depth
14692     51/push-ecx
14693     68/push 0x11/imm32/alloc-id:fake
14694     68/push 0/imm32/name
14695     68/push 0/imm32/name
14696     68/push 0x11/imm32/alloc-id:fake:payload
14697     89/<- %ecx 4/r32/esp
14698 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
14699     # var-foo->name = "foo"
14700     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14701     (copy-array Heap "foo" %eax)
14702 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
14703     # var-foo->register = "eax"
14704     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14705     (copy-array Heap "eax" %eax)
14706 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
14707     # var operand/ebx: (payload stmt-var)
14708     68/push 0/imm32/is-deref:false
14709     68/push 0/imm32/next
14710     68/push 0/imm32/next
14711     51/push-ecx/var-foo
14712     68/push 0x11/imm32/alloc-id:fake
14713     68/push 0x11/imm32/alloc-id:fake:payload
14714     89/<- %ebx 4/r32/esp
14715 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
14716     # var stmt/esi: (addr statement)
14717     68/push 0/imm32/no-outputs
14718     68/push 0/imm32/no-outputs
14719     53/push-ebx/inouts
14720     68/push 0x11/imm32/alloc-id:fake
14721     68/push 0/imm32/operation
14722     68/push 0/imm32/operation
14723     68/push 1/imm32
14724     89/<- %esi 4/r32/esp
14725 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
14726     # stmt->operation = "increment"
14727     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14728     (copy-array Heap "increment" %eax)
14729 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
14730     # var formal-var/ebx: (payload var)
14731     68/push 0/imm32/register
14732     68/push 0/imm32/register
14733     68/push 0/imm32/no-stack-offset
14734     68/push 1/imm32/block-depth
14735     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
14736     68/push 0x11/imm32/alloc-id:fake
14737     68/push 0/imm32/name
14738     68/push 0/imm32/name
14739     68/push 0x11/imm32/alloc-id:fake:payload
14740     89/<- %ebx 4/r32/esp
14741 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
14742     # formal-var->name = "dummy"
14743     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
14744     (copy-array Heap "dummy" %eax)
14745 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
14746     # formal-var->register = "*"
14747     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
14748     (copy-array Heap "*" %eax)  # Any-register
14749 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
14750     # var formal-outputs/ebx: (payload list stmt-var)
14751     68/push 0/imm32/next
14752     68/push 0/imm32/next
14753     53/push-ebx/formal-var
14754     68/push 0x11/imm32/alloc-id:fake
14755     68/push 0x11/imm32/alloc-id:fake:payload
14756     89/<- %ebx 4/r32/esp
14757 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
14758     # var primitive2/edi: (payload primitive)
14759     68/push 0/imm32/next
14760     68/push 0/imm32/next
14761     68/push 0/imm32/output-is-write-only
14762     68/push 0/imm32/no-disp32
14763     68/push 0/imm32/no-imm32
14764     68/push 0/imm32/no-r32
14765     68/push 3/imm32/rm32-is-first-output
14766     68/push 0/imm32/subx-name
14767     68/push 0/imm32/subx-name
14768     53/push-ebx/outputs
14769     68/push 0x11/imm32/alloc-id:fake
14770     68/push 0/imm32/no-inouts
14771     68/push 0/imm32/no-inouts
14772     68/push 0/imm32/name
14773     68/push 0/imm32/name
14774     68/push 0x11/imm32/alloc-id:fake:payload
14775     89/<- %edi 4/r32/esp
14776 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
14777     # primitives->name = "increment"
14778     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
14779     (copy-array Heap "increment" %eax)
14780 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
14781     # primitives->subx-name = "ff 0/subop/increment"
14782     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
14783     (copy-array Heap "ff 0/subop/increment" %eax)
14784 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
14785     # var primitives/ebx: (addr primitive)
14786     57/push-edi
14787     68/push 0x11/imm32/alloc-id:fake
14788     68/push 0/imm32/output-is-write-only
14789     68/push 0/imm32/no-disp32
14790     68/push 0/imm32/no-imm32
14791     68/push 0/imm32/no-r32
14792     68/push 1/imm32/rm32-is-first-inout
14793     68/push 0/imm32/subx-name
14794     68/push 0/imm32/subx-name
14795     68/push 0/imm32/no-outputs
14796     68/push 0/imm32/no-outputs
14797     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
14798     68/push 0x11/imm32/alloc-id:fake
14799     68/push 0/imm32/name
14800     68/push 0/imm32/name
14801     89/<- %ebx 4/r32/esp
14802 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
14803     # primitives->name = "increment"
14804     (copy-array Heap "increment" %ebx)  # Primitive-name
14805 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
14806     # primitives->subx-name = "ff 0/subop/increment"
14807     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
14808     (copy-array Heap "ff 0/subop/increment" %eax)
14809     # convert
14810     c7 0/subop/copy *Curr-block-depth 0/imm32
14811     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
14812     (flush _test-output-buffered-file)
14813 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14819     # check output
14820     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
14821     # . epilogue
14822     89/<- %esp 5/r32/ebp
14823     5d/pop-to-ebp
14824     c3/return
14825 
14826 test-increment-register:
14827     # Select the right register between overloads.
14828     #   foo <- increment
14829     # =>
14830     #   50/increment-eax
14831     #
14832     # There's a variable on the var stack as follows:
14833     #   name: 'foo'
14834     #   type: int
14835     #   register: 'eax'
14836     #
14837     # Primitives are the global definitions.
14838     #
14839     # . prologue
14840     55/push-ebp
14841     89/<- %ebp 4/r32/esp
14842     # setup
14843     (clear-stream _test-output-stream)
14844     (clear-stream $_test-output-buffered-file->buffer)
14845 $test-increment-register:initialize-type:
14846     # var type/ecx: (payload tree type-id) = int
14847     68/push 0/imm32/right:null
14848     68/push 0/imm32/right:null
14849     68/push 0/imm32/left:unused
14850     68/push 1/imm32/value:int
14851     68/push 1/imm32/is-atom?:true
14852     68/push 0x11/imm32/alloc-id:fake:payload
14853     89/<- %ecx 4/r32/esp
14854 $test-increment-register:initialize-var:
14855     # var var-foo/ecx: (payload var)
14856     68/push 0/imm32/register
14857     68/push 0/imm32/register
14858     68/push 0/imm32/no-stack-offset
14859     68/push 1/imm32/block-depth
14860     51/push-ecx
14861     68/push 0x11/imm32/alloc-id:fake
14862     68/push 0/imm32/name
14863     68/push 0/imm32/name
14864     68/push 0x11/imm32/alloc-id:fake:payload
14865     89/<- %ecx 4/r32/esp
14866 $test-increment-register:initialize-var-name:
14867     # var-foo->name = "foo"
14868     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14869     (copy-array Heap "foo" %eax)
14870 $test-increment-register:initialize-var-register:
14871     # var-foo->register = "eax"
14872     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14873     (copy-array Heap "eax" %eax)
14874 $test-increment-register:initialize-stmt-var:
14875     # var operand/ebx: (payload stmt-var)
14876     68/push 0/imm32/is-deref:false
14877     68/push 0/imm32/next
14878     68/push 0/imm32/next
14879     51/push-ecx/var-foo
14880     68/push 0x11/imm32/alloc-id:fake
14881     68/push 0x11/imm32/alloc-id:fake:payload
14882     89/<- %ebx 4/r32/esp
14883 $test-increment-register:initialize-stmt:
14884     # var stmt/esi: (addr statement)
14885     53/push-ebx/outputs
14886     68/push 0x11/imm32/alloc-id:fake
14887     68/push 0/imm32/no-inouts
14888     68/push 0/imm32/no-inouts
14889     68/push 0/imm32/operation
14890     68/push 0/imm32/operation
14891     68/push 1/imm32
14892     89/<- %esi 4/r32/esp
14893 $test-increment-register:initialize-stmt-operation:
14894     # stmt->operation = "increment"
14895     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
14896     (copy-array Heap "increment" %eax)
14897     # convert
14898     c7 0/subop/copy *Curr-block-depth 0/imm32
14899     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
14900     (flush _test-output-buffered-file)
14901 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
14907     # check output
14908     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
14909     # . epilogue
14910     89/<- %esp 5/r32/ebp
14911     5d/pop-to-ebp
14912     c3/return
14913 
14914 test-add-reg-to-reg:
14915     #   var1/reg <- add var2/reg
14916     # =>
14917     #   01/add-to %var1 var2
14918     #
14919     # . prologue
14920     55/push-ebp
14921     89/<- %ebp 4/r32/esp
14922     # setup
14923     (clear-stream _test-output-stream)
14924     (clear-stream $_test-output-buffered-file->buffer)
14925 $test-add-reg-to-reg:initialize-type:
14926     # var type/ecx: (payload tree type-id) = int
14927     68/push 0/imm32/right:null
14928     68/push 0/imm32/right:null
14929     68/push 0/imm32/left:unused
14930     68/push 1/imm32/value:int
14931     68/push 1/imm32/is-atom?:true
14932     68/push 0x11/imm32/alloc-id:fake:payload
14933     89/<- %ecx 4/r32/esp
14934 $test-add-reg-to-reg:initialize-var1:
14935     # var var1/ecx: (payload var)
14936     68/push 0/imm32/register
14937     68/push 0/imm32/register
14938     68/push 0/imm32/no-stack-offset
14939     68/push 1/imm32/block-depth
14940     51/push-ecx
14941     68/push 0x11/imm32/alloc-id:fake
14942     68/push 0/imm32/name
14943     68/push 0/imm32/name
14944     68/push 0x11/imm32/alloc-id:fake:payload
14945     89/<- %ecx 4/r32/esp
14946 $test-add-reg-to-reg:initialize-var1-name:
14947     # var1->name = "var1"
14948     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
14949     (copy-array Heap "var1" %eax)
14950 $test-add-reg-to-reg:initialize-var1-register:
14951     # var1->register = "eax"
14952     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
14953     (copy-array Heap "eax" %eax)
14954 $test-add-reg-to-reg:initialize-var2:
14955     # var var2/edx: (payload var)
14956     68/push 0/imm32/register
14957     68/push 0/imm32/register
14958     68/push 0/imm32/no-stack-offset
14959     68/push 1/imm32/block-depth
14960     ff 6/subop/push *(ecx+0x10)
14961     68/push 0x11/imm32/alloc-id:fake
14962     68/push 0/imm32/name
14963     68/push 0/imm32/name
14964     68/push 0x11/imm32/alloc-id:fake:payload
14965     89/<- %edx 4/r32/esp
14966 $test-add-reg-to-reg:initialize-var2-name:
14967     # var2->name = "var2"
14968     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
14969     (copy-array Heap "var2" %eax)
14970 $test-add-reg-to-reg:initialize-var2-register:
14971     # var2->register = "ecx"
14972     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
14973     (copy-array Heap "ecx" %eax)
14974 $test-add-reg-to-reg:initialize-inouts:
14975     # var inouts/esi: (payload stmt-var) = [var2]
14976     68/push 0/imm32/is-deref:false
14977     68/push 0/imm32/next
14978     68/push 0/imm32/next
14979     52/push-edx/var2
14980     68/push 0x11/imm32/alloc-id:fake
14981     68/push 0x11/imm32/alloc-id:fake:payload
14982     89/<- %esi 4/r32/esp
14983 $test-add-reg-to-reg:initialize-outputs:
14984     # var outputs/edi: (payload stmt-var) = [var1]
14985     68/push 0/imm32/is-deref:false
14986     68/push 0/imm32/next
14987     68/push 0/imm32/next
14988     51/push-ecx/var1
14989     68/push 0x11/imm32/alloc-id:fake
14990     68/push 0x11/imm32/alloc-id:fake:payload
14991     89/<- %edi 4/r32/esp
14992 $test-add-reg-to-reg:initialize-stmt:
14993     # var stmt/esi: (addr statement)
14994     68/push 0/imm32/next
14995     68/push 0/imm32/next
14996     57/push-edi/outputs
14997     68/push 0x11/imm32/alloc-id:fake
14998     56/push-esi/inouts
14999     68/push 0x11/imm32/alloc-id:fake
15000     68/push 0/imm32/operation
15001     68/push 0/imm32/operation
15002     68/push 1/imm32/tag:stmt1
15003     89/<- %esi 4/r32/esp
15004 $test-add-reg-to-reg:initialize-stmt-operation:
15005     # stmt->operation = "add"
15006     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15007     (copy-array Heap "add" %eax)
15008     # convert
15009     c7 0/subop/copy *Curr-block-depth 0/imm32
15010     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15011     (flush _test-output-buffered-file)
15012 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15018     # check output
15019     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
15020     # . epilogue
15021     89/<- %esp 5/r32/ebp
15022     5d/pop-to-ebp
15023     c3/return
15024 
15025 test-add-reg-to-mem:
15026     #   add-to var1 var2/reg
15027     # =>
15028     #   01/add-to *(ebp+__) var2
15029     #
15030     # . prologue
15031     55/push-ebp
15032     89/<- %ebp 4/r32/esp
15033     # setup
15034     (clear-stream _test-output-stream)
15035     (clear-stream $_test-output-buffered-file->buffer)
15036 $test-add-reg-to-mem:initialize-type:
15037     # var type/ecx: (payload tree type-id) = int
15038     68/push 0/imm32/right:null
15039     68/push 0/imm32/right:null
15040     68/push 0/imm32/left:unused
15041     68/push 1/imm32/value:int
15042     68/push 1/imm32/is-atom?:true
15043     68/push 0x11/imm32/alloc-id:fake:payload
15044     89/<- %ecx 4/r32/esp
15045 $test-add-reg-to-mem:initialize-var1:
15046     # var var1/ecx: (payload var)
15047     68/push 0/imm32/register
15048     68/push 0/imm32/register
15049     68/push 8/imm32/stack-offset
15050     68/push 1/imm32/block-depth
15051     51/push-ecx
15052     68/push 0x11/imm32/alloc-id:fake
15053     68/push 0/imm32/name
15054     68/push 0/imm32/name
15055     68/push 0x11/imm32/alloc-id:fake:payload
15056     89/<- %ecx 4/r32/esp
15057 $test-add-reg-to-mem:initialize-var1-name:
15058     # var1->name = "var1"
15059     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15060     (copy-array Heap "var1" %eax)
15061 $test-add-reg-to-mem:initialize-var2:
15062     # var var2/edx: (payload var)
15063     68/push 0/imm32/register
15064     68/push 0/imm32/register
15065     68/push 0/imm32/no-stack-offset
15066     68/push 1/imm32/block-depth
15067     ff 6/subop/push *(ecx+0x10)
15068     68/push 0x11/imm32/alloc-id:fake
15069     68/push 0/imm32/name
15070     68/push 0/imm32/name
15071     68/push 0x11/imm32/alloc-id:fake:payload
15072     89/<- %edx 4/r32/esp
15073 $test-add-reg-to-mem:initialize-var2-name:
15074     # var2->name = "var2"
15075     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15076     (copy-array Heap "var2" %eax)
15077 $test-add-reg-to-mem:initialize-var2-register:
15078     # var2->register = "ecx"
15079     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
15080     (copy-array Heap "ecx" %eax)
15081 $test-add-reg-to-mem:initialize-inouts:
15082     # var inouts/esi: (payload stmt-var) = [var2]
15083     68/push 0/imm32/is-deref:false
15084     68/push 0/imm32/next
15085     68/push 0/imm32/next
15086     52/push-edx/var2
15087     68/push 0x11/imm32/alloc-id:fake
15088     68/push 0x11/imm32/alloc-id:fake:payload
15089     89/<- %esi 4/r32/esp
15090     # inouts = [var1, var2]
15091     68/push 0/imm32/is-deref:false
15092     56/push-esi/next
15093     68/push 0x11/imm32/alloc-id:fake
15094     51/push-ecx/var1
15095     68/push 0x11/imm32/alloc-id:fake
15096     68/push 0x11/imm32/alloc-id:fake:payload
15097     89/<- %esi 4/r32/esp
15098 $test-add-reg-to-mem:initialize-stmt:
15099     # var stmt/esi: (addr statement)
15100     68/push 0/imm32/next
15101     68/push 0/imm32/next
15102     68/push 0/imm32/outputs
15103     68/push 0/imm32/outputs
15104     56/push-esi/inouts
15105     68/push 0x11/imm32/alloc-id:fake
15106     68/push 0/imm32/operation
15107     68/push 0/imm32/operation
15108     68/push 1/imm32/tag:stmt1
15109     89/<- %esi 4/r32/esp
15110 $test-add-reg-to-mem:initialize-stmt-operation:
15111     # stmt->operation = "add-to"
15112     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15113     (copy-array Heap "add-to" %eax)
15114     # convert
15115     c7 0/subop/copy *Curr-block-depth 0/imm32
15116     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15117     (flush _test-output-buffered-file)
15118 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15124     # check output
15125     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
15126     # . epilogue
15127     89/<- %esp 5/r32/ebp
15128     5d/pop-to-ebp
15129     c3/return
15130 
15131 test-add-mem-to-reg:
15132     #   var1/reg <- add var2
15133     # =>
15134     #   03/add *(ebp+__) var1
15135     #
15136     # . prologue
15137     55/push-ebp
15138     89/<- %ebp 4/r32/esp
15139     # setup
15140     (clear-stream _test-output-stream)
15141     (clear-stream $_test-output-buffered-file->buffer)
15142 $test-add-mem-to-reg:initialize-type:
15143     # var type/ecx: (payload tree type-id) = int
15144     68/push 0/imm32/right:null
15145     68/push 0/imm32/right:null
15146     68/push 0/imm32/left:unused
15147     68/push 1/imm32/value:int
15148     68/push 1/imm32/is-atom?:true
15149     68/push 0x11/imm32/alloc-id:fake:payload
15150     89/<- %ecx 4/r32/esp
15151 $test-add-mem-to-reg:initialize-var:
15152     # var var1/ecx: (payload var)
15153     68/push 0/imm32/register
15154     68/push 0/imm32/register
15155     68/push 0/imm32/no-stack-offset
15156     68/push 1/imm32/block-depth
15157     51/push-ecx
15158     68/push 0x11/imm32/alloc-id:fake
15159     68/push 0/imm32/name
15160     68/push 0/imm32/name
15161     68/push 0x11/imm32/alloc-id:fake:payload
15162     89/<- %ecx 4/r32/esp
15163 $test-add-mem-to-reg:initialize-var-name:
15164     # var1->name = "foo"
15165     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15166     (copy-array Heap "var1" %eax)
15167 $test-add-mem-to-reg:initialize-var-register:
15168     # var1->register = "eax"
15169     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15170     (copy-array Heap "eax" %eax)
15171 $test-add-mem-to-reg:initialize-var2:
15172     # var var2/edx: (payload var)
15173     68/push 0/imm32/register
15174     68/push 0/imm32/register
15175     68/push 8/imm32/stack-offset
15176     68/push 1/imm32/block-depth
15177     ff 6/subop/push *(ecx+0x10)
15178     68/push 0x11/imm32/alloc-id:fake
15179     68/push 0/imm32/name
15180     68/push 0/imm32/name
15181     68/push 0x11/imm32/alloc-id:fake:payload
15182     89/<- %edx 4/r32/esp
15183 $test-add-mem-to-reg:initialize-var2-name:
15184     # var2->name = "var2"
15185     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15186     (copy-array Heap "var2" %eax)
15187 $test-add-mem-to-reg:initialize-inouts:
15188     # var inouts/esi: (payload stmt-var) = [var2]
15189     68/push 0/imm32/is-deref:false
15190     68/push 0/imm32/next
15191     68/push 0/imm32/next
15192     52/push-edx/var2
15193     68/push 0x11/imm32/alloc-id:fake
15194     68/push 0x11/imm32/alloc-id:fake:payload
15195     89/<- %esi 4/r32/esp
15196 $test-add-mem-to-reg:initialize-outputs:
15197     # var outputs/edi: (payload stmt-var) = [var1]
15198     68/push 0/imm32/is-deref:false
15199     68/push 0/imm32/next
15200     68/push 0/imm32/next
15201     51/push-ecx/var1
15202     68/push 0x11/imm32/alloc-id:fake
15203     68/push 0x11/imm32/alloc-id:fake:payload
15204     89/<- %edi 4/r32/esp
15205 $test-add-mem-to-reg:initialize-stmt:
15206     # var stmt/esi: (addr statement)
15207     68/push 0/imm32/next
15208     68/push 0/imm32/next
15209     57/push-edi/outputs
15210     68/push 0x11/imm32/alloc-id:fake
15211     56/push-esi/inouts
15212     68/push 0x11/imm32/alloc-id:fake
15213     68/push 0/imm32/operation
15214     68/push 0/imm32/operation
15215     68/push 1/imm32/tag:stmt1
15216     89/<- %esi 4/r32/esp
15217 $test-add-mem-to-reg:initialize-stmt-operation:
15218     # stmt->operation = "add"
15219     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15220     (copy-array Heap "add" %eax)
15221     # convert
15222     c7 0/subop/copy *Curr-block-depth 0/imm32
15223     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15224     (flush _test-output-buffered-file)
15225 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15231     # check output
15232     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
15233     # . epilogue
15234     89/<- %esp 5/r32/ebp
15235     5d/pop-to-ebp
15236     c3/return
15237 
15238 test-add-literal-to-eax:
15239     #   var1/eax <- add 0x34
15240     # =>
15241     #   05/add-to-eax 0x34/imm32
15242     #
15243     # . prologue
15244     55/push-ebp
15245     89/<- %ebp 4/r32/esp
15246     # setup
15247     (clear-stream _test-output-stream)
15248     (clear-stream $_test-output-buffered-file->buffer)
15249 $test-add-literal-to-eax:initialize-var-type:
15250     # var type/ecx: (payload tree type-id) = int
15251     68/push 0/imm32/right:null
15252     68/push 0/imm32/right:null
15253     68/push 0/imm32/left:unused
15254     68/push 1/imm32/value:int
15255     68/push 1/imm32/is-atom?:true
15256     68/push 0x11/imm32/alloc-id:fake:payload
15257     89/<- %ecx 4/r32/esp
15258 $test-add-literal-to-eax:initialize-var:
15259     # var v/ecx: (payload var)
15260     68/push 0/imm32/register
15261     68/push 0/imm32/register
15262     68/push 0/imm32/no-stack-offset
15263     68/push 1/imm32/block-depth
15264     51/push-ecx
15265     68/push 0x11/imm32/alloc-id:fake
15266     68/push 0/imm32/name
15267     68/push 0/imm32/name
15268     68/push 0x11/imm32/alloc-id:fake:payload
15269     89/<- %ecx 4/r32/esp
15270 $test-add-literal-to-eax:initialize-var-name:
15271     # v->name = "v"
15272     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15273     (copy-array Heap "v" %eax)
15274 $test-add-literal-to-eax:initialize-var-register:
15275     # v->register = "eax"
15276     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15277     (copy-array Heap "eax" %eax)
15278 $test-add-literal-to-eax:initialize-literal-type:
15279     # var type/edx: (payload tree type-id) = literal
15280     68/push 0/imm32/right:null
15281     68/push 0/imm32/right:null
15282     68/push 0/imm32/left:unused
15283     68/push 0/imm32/value:literal
15284     68/push 1/imm32/is-atom?:true
15285     68/push 0x11/imm32/alloc-id:fake:payload
15286     89/<- %edx 4/r32/esp
15287 $test-add-literal-to-eax:initialize-literal:
15288     # var l/edx: (payload var)
15289     68/push 0/imm32/register
15290     68/push 0/imm32/register
15291     68/push 0/imm32/no-stack-offset
15292     68/push 1/imm32/block-depth
15293     52/push-edx
15294     68/push 0x11/imm32/alloc-id:fake
15295     68/push 0/imm32/name
15296     68/push 0/imm32/name
15297     68/push 0x11/imm32/alloc-id:fake:payload
15298     89/<- %edx 4/r32/esp
15299 $test-add-literal-to-eax:initialize-literal-value:
15300     # l->name = "0x34"
15301     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15302     (copy-array Heap "0x34" %eax)
15303 $test-add-literal-to-eax:initialize-inouts:
15304     # var inouts/esi: (payload stmt-var) = [l]
15305     68/push 0/imm32/is-deref:false
15306     68/push 0/imm32/next
15307     68/push 0/imm32/next
15308     52/push-edx/l
15309     68/push 0x11/imm32/alloc-id:fake
15310     68/push 0x11/imm32/alloc-id:fake:payload
15311     89/<- %esi 4/r32/esp
15312 $test-add-literal-to-eax:initialize-outputs:
15313     # var outputs/edi: (payload stmt-var) = [v]
15314     68/push 0/imm32/is-deref:false
15315     68/push 0/imm32/next
15316     68/push 0/imm32/next
15317     51/push-ecx/v
15318     68/push 0x11/imm32/alloc-id:fake
15319     68/push 0x11/imm32/alloc-id:fake:payload
15320     89/<- %edi 4/r32/esp
15321 $test-add-literal-to-eax:initialize-stmt:
15322     # var stmt/esi: (addr statement)
15323     68/push 0/imm32/next
15324     68/push 0/imm32/next
15325     57/push-edi/outputs
15326     68/push 0x11/imm32/alloc-id:fake
15327     56/push-esi/inouts
15328     68/push 0x11/imm32/alloc-id:fake
15329     68/push 0/imm32/operation
15330     68/push 0/imm32/operation
15331     68/push 1/imm32/tag:stmt1
15332     89/<- %esi 4/r32/esp
15333 $test-add-literal-to-eax:initialize-stmt-operation:
15334     # stmt->operation = "add"
15335     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15336     (copy-array Heap "add" %eax)
15337     # convert
15338     c7 0/subop/copy *Curr-block-depth 0/imm32
15339     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15340     (flush _test-output-buffered-file)
15341 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15347     # check output
15348     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
15349     # . epilogue
15350     89/<- %esp 5/r32/ebp
15351     5d/pop-to-ebp
15352     c3/return
15353 
15354 test-add-literal-to-reg:
15355     #   var1/ecx <- add 0x34
15356     # =>
15357     #   81 0/subop/add %ecx 0x34/imm32
15358     #
15359     # . prologue
15360     55/push-ebp
15361     89/<- %ebp 4/r32/esp
15362     # setup
15363     (clear-stream _test-output-stream)
15364     (clear-stream $_test-output-buffered-file->buffer)
15365 $test-add-literal-to-reg:initialize-var-type:
15366     # var type/ecx: (payload tree type-id) = int
15367     68/push 0/imm32/right:null
15368     68/push 0/imm32/right:null
15369     68/push 0/imm32/left:unused
15370     68/push 1/imm32/value:int
15371     68/push 1/imm32/is-atom?:true
15372     68/push 0x11/imm32/alloc-id:fake:payload
15373     89/<- %ecx 4/r32/esp
15374 $test-add-literal-to-reg:initialize-var:
15375     # var v/ecx: (payload var)
15376     68/push 0/imm32/register
15377     68/push 0/imm32/register
15378     68/push 0/imm32/no-stack-offset
15379     68/push 1/imm32/block-depth
15380     51/push-ecx
15381     68/push 0x11/imm32/alloc-id:fake
15382     68/push 0/imm32/name
15383     68/push 0/imm32/name
15384     68/push 0x11/imm32/alloc-id:fake:payload
15385     89/<- %ecx 4/r32/esp
15386 $test-add-literal-to-reg:initialize-var-name:
15387     # v->name = "v"
15388     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15389     (copy-array Heap "v" %eax)
15390 $test-add-literal-to-reg:initialize-var-register:
15391     # v->register = "ecx"
15392     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15393     (copy-array Heap "ecx" %eax)
15394 $test-add-literal-to-reg:initialize-literal-type:
15395     # var type/edx: (payload tree type-id) = literal
15396     68/push 0/imm32/right:null
15397     68/push 0/imm32/right:null
15398     68/push 0/imm32/left:unused
15399     68/push 0/imm32/value:literal
15400     68/push 1/imm32/is-atom?:true
15401     68/push 0x11/imm32/alloc-id:fake:payload
15402     89/<- %edx 4/r32/esp
15403 $test-add-literal-to-reg:initialize-literal:
15404     # var l/edx: (payload var)
15405     68/push 0/imm32/register
15406     68/push 0/imm32/register
15407     68/push 0/imm32/no-stack-offset
15408     68/push 1/imm32/block-depth
15409     52/push-edx
15410     68/push 0x11/imm32/alloc-id:fake
15411     68/push 0/imm32/name
15412     68/push 0/imm32/name
15413     68/push 0x11/imm32/alloc-id:fake:payload
15414     89/<- %edx 4/r32/esp
15415 $test-add-literal-to-reg:initialize-literal-value:
15416     # l->name = "0x34"
15417     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15418     (copy-array Heap "0x34" %eax)
15419 $test-add-literal-to-reg:initialize-inouts:
15420     # var inouts/esi: (payload stmt-var) = [l]
15421     68/push 0/imm32/is-deref:false
15422     68/push 0/imm32/next
15423     68/push 0/imm32/next
15424     52/push-edx/l
15425     68/push 0x11/imm32/alloc-id:fake
15426     68/push 0x11/imm32/alloc-id:fake:payload
15427     89/<- %esi 4/r32/esp
15428 $test-add-literal-to-reg:initialize-outputs:
15429     # var outputs/edi: (payload stmt-var) = [v]
15430     68/push 0/imm32/is-deref:false
15431     68/push 0/imm32/next
15432     68/push 0/imm32/next
15433     51/push-ecx/v
15434     68/push 0x11/imm32/alloc-id:fake
15435     68/push 0x11/imm32/alloc-id:fake:payload
15436     89/<- %edi 4/r32/esp
15437 $test-add-literal-to-reg:initialize-stmt:
15438     # var stmt/esi: (addr statement)
15439     68/push 0/imm32/next
15440     68/push 0/imm32/next
15441     57/push-edi/outputs
15442     68/push 0x11/imm32/alloc-id:fake
15443     56/push-esi/inouts
15444     68/push 0x11/imm32/alloc-id:fake
15445     68/push 0/imm32/operation
15446     68/push 0/imm32/operation
15447     68/push 1/imm32/tag:stmt1
15448     89/<- %esi 4/r32/esp
15449 $test-add-literal-to-reg:initialize-stmt-operation:
15450     # stmt->operation = "add"
15451     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15452     (copy-array Heap "add" %eax)
15453     # convert
15454     c7 0/subop/copy *Curr-block-depth 0/imm32
15455     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15456     (flush _test-output-buffered-file)
15457 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15463     # check output
15464     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
15465     # . epilogue
15466     89/<- %esp 5/r32/ebp
15467     5d/pop-to-ebp
15468     c3/return
15469 
15470 test-add-literal-to-mem:
15471     #   add-to var1, 0x34
15472     # =>
15473     #   81 0/subop/add %eax 0x34/imm32
15474     #
15475     # . prologue
15476     55/push-ebp
15477     89/<- %ebp 4/r32/esp
15478     # setup
15479     (clear-stream _test-output-stream)
15480     (clear-stream $_test-output-buffered-file->buffer)
15481 $test-add-literal-to-mem:initialize-type:
15482     # var type/ecx: (payload tree type-id) = int
15483     68/push 0/imm32/right:null
15484     68/push 0/imm32/right:null
15485     68/push 0/imm32/left:unused
15486     68/push 1/imm32/value:int
15487     68/push 1/imm32/is-atom?:true
15488     68/push 0x11/imm32/alloc-id:fake:payload
15489     89/<- %ecx 4/r32/esp
15490 $test-add-literal-to-mem:initialize-var1:
15491     # var var1/ecx: (payload var)
15492     68/push 0/imm32/register
15493     68/push 0/imm32/register
15494     68/push 8/imm32/stack-offset
15495     68/push 1/imm32/block-depth
15496     51/push-ecx
15497     68/push 0x11/imm32/alloc-id:fake
15498     68/push 0/imm32/name
15499     68/push 0/imm32/name
15500     68/push 0x11/imm32/alloc-id:fake:payload
15501     89/<- %ecx 4/r32/esp
15502 $test-add-literal-to-mem:initialize-var1-name:
15503     # var1->name = "var1"
15504     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15505     (copy-array Heap "var1" %eax)
15506 $test-add-literal-to-mem:initialize-literal-type:
15507     # var type/edx: (payload tree type-id) = literal
15508     68/push 0/imm32/right:null
15509     68/push 0/imm32/right:null
15510     68/push 0/imm32/left:unused
15511     68/push 0/imm32/value:literal
15512     68/push 1/imm32/is-atom?:true
15513     68/push 0x11/imm32/alloc-id:fake:payload
15514     89/<- %edx 4/r32/esp
15515 $test-add-literal-to-mem:initialize-literal:
15516     # var l/edx: (payload var)
15517     68/push 0/imm32/register
15518     68/push 0/imm32/register
15519     68/push 0/imm32/no-stack-offset
15520     68/push 1/imm32/block-depth
15521     52/push-edx
15522     68/push 0x11/imm32/alloc-id:fake
15523     68/push 0/imm32/name
15524     68/push 0/imm32/name
15525     68/push 0x11/imm32/alloc-id:fake:payload
15526     89/<- %edx 4/r32/esp
15527 $test-add-literal-to-mem:initialize-literal-value:
15528     # l->name = "0x34"
15529     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15530     (copy-array Heap "0x34" %eax)
15531 $test-add-literal-to-mem:initialize-inouts:
15532     # var inouts/esi: (payload stmt-var) = [l]
15533     68/push 0/imm32/is-deref:false
15534     68/push 0/imm32/next
15535     68/push 0/imm32/next
15536     52/push-edx/l
15537     68/push 0x11/imm32/alloc-id:fake
15538     68/push 0x11/imm32/alloc-id:fake:payload
15539     89/<- %esi 4/r32/esp
15540     # var inouts = (handle stmt-var) = [var1, var2]
15541     68/push 0/imm32/is-deref:false
15542     56/push-esi/next
15543     68/push 0x11/imm32/alloc-id:fake
15544     51/push-ecx/var1
15545     68/push 0x11/imm32/alloc-id:fake
15546     68/push 0x11/imm32/alloc-id:fake:payload
15547     89/<- %esi 4/r32/esp
15548 $test-add-literal-to-mem:initialize-stmt:
15549     # var stmt/esi: (addr statement)
15550     68/push 0/imm32/next
15551     68/push 0/imm32/next
15552     68/push 0/imm32/outputs
15553     68/push 0/imm32/outputs
15554     56/push-esi/inouts
15555     68/push 0x11/imm32/alloc-id:fake
15556     68/push 0/imm32/operation
15557     68/push 0/imm32/operation
15558     68/push 1/imm32/tag:stmt1
15559     89/<- %esi 4/r32/esp
15560 $test-add-literal-to-mem:initialize-stmt-operation:
15561     # stmt->operation = "add-to"
15562     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15563     (copy-array Heap "add-to" %eax)
15564     # convert
15565     c7 0/subop/copy *Curr-block-depth 0/imm32
15566     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15567     (flush _test-output-buffered-file)
15568 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15574     # check output
15575     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
15576     # . epilogue
15577     89/<- %esp 5/r32/ebp
15578     5d/pop-to-ebp
15579     c3/return
15580 
15581 test-compare-mem-with-reg:
15582     #   compare var1, var2/eax
15583     # =>
15584     #   39/compare *(ebp+___) 0/r32/eax
15585     #
15586     # . prologue
15587     55/push-ebp
15588     89/<- %ebp 4/r32/esp
15589     # setup
15590     (clear-stream _test-output-stream)
15591     (clear-stream $_test-output-buffered-file->buffer)
15592 $test-compare-mem-with-reg:initialize-type:
15593     # var type/ecx: (payload tree type-id) = int
15594     68/push 0/imm32/right:null
15595     68/push 0/imm32/right:null
15596     68/push 0/imm32/left:unused
15597     68/push 1/imm32/value:int
15598     68/push 1/imm32/is-atom?:true
15599     68/push 0x11/imm32/alloc-id:fake:payload
15600     89/<- %ecx 4/r32/esp
15601 $test-compare-mem-with-reg:initialize-var1:
15602     # var var1/ecx: (payload var)
15603     68/push 0/imm32/register
15604     68/push 0/imm32/register
15605     68/push 8/imm32/stack-offset
15606     68/push 1/imm32/block-depth
15607     51/push-ecx
15608     68/push 0x11/imm32/alloc-id:fake
15609     68/push 0/imm32/name
15610     68/push 0/imm32/name
15611     68/push 0x11/imm32/alloc-id:fake:payload
15612     89/<- %ecx 4/r32/esp
15613 $test-compare-mem-with-reg:initialize-var1-name:
15614     # var1->name = "var1"
15615     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15616     (copy-array Heap "var1" %eax)
15617 $test-compare-mem-with-reg:initialize-var2:
15618     # var var2/edx: (payload var)
15619     68/push 0/imm32/register
15620     68/push 0/imm32/register
15621     68/push 0/imm32/no-stack-offset
15622     68/push 1/imm32/block-depth
15623     ff 6/subop/push *(ecx+0x10)
15624     68/push 0x11/imm32/alloc-id:fake
15625     68/push 0/imm32/name
15626     68/push 0/imm32/name
15627     68/push 0x11/imm32/alloc-id:fake:payload
15628     89/<- %edx 4/r32/esp
15629 $test-compare-mem-with-reg:initialize-var2-name:
15630     # var2->name = "var2"
15631     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15632     (copy-array Heap "var2" %eax)
15633 $test-compare-mem-with-reg:initialize-var2-register:
15634     # var2->register = "eax"
15635     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
15636     (copy-array Heap "eax" %eax)
15637 $test-compare-mem-with-reg:initialize-inouts:
15638     # var inouts/esi: (payload stmt-var) = [var2]
15639     68/push 0/imm32/is-deref:false
15640     68/push 0/imm32/next
15641     68/push 0/imm32/next
15642     52/push-edx/var2
15643     68/push 0x11/imm32/alloc-id:fake
15644     68/push 0x11/imm32/alloc-id:fake:payload
15645     89/<- %esi 4/r32/esp
15646     # inouts = [var1, var2]
15647     68/push 0/imm32/is-deref:false
15648     56/push-esi/next
15649     68/push 0x11/imm32/alloc-id:fake
15650     51/push-ecx/var1
15651     68/push 0x11/imm32/alloc-id:fake
15652     68/push 0x11/imm32/alloc-id:fake:payload
15653     89/<- %esi 4/r32/esp
15654 $test-compare-mem-with-reg:initialize-stmt:
15655     # var stmt/esi: (addr statement)
15656     68/push 0/imm32/next
15657     68/push 0/imm32/next
15658     68/push 0/imm32/outputs
15659     68/push 0/imm32/outputs
15660     56/push-esi/inouts
15661     68/push 0x11/imm32/alloc-id:fake
15662     68/push 0/imm32/operation
15663     68/push 0/imm32/operation
15664     68/push 1/imm32/tag:stmt1
15665     89/<- %esi 4/r32/esp
15666 $test-compare-mem-with-reg:initialize-stmt-operation:
15667     # stmt->operation = "compare"
15668     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15669     (copy-array Heap "compare" %eax)
15670     # convert
15671     c7 0/subop/copy *Curr-block-depth 0/imm32
15672     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15673     (flush _test-output-buffered-file)
15674 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15680     # check output
15681     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
15682     # . epilogue
15683     89/<- %esp 5/r32/ebp
15684     5d/pop-to-ebp
15685     c3/return
15686 
15687 test-compare-reg-with-mem:
15688     #   compare var1/eax, var2
15689     # =>
15690     #   3b/compare<- *(ebp+___) 0/r32/eax
15691     #
15692     # . prologue
15693     55/push-ebp
15694     89/<- %ebp 4/r32/esp
15695     # setup
15696     (clear-stream _test-output-stream)
15697     (clear-stream $_test-output-buffered-file->buffer)
15698 $test-compare-reg-with-mem:initialize-type:
15699     # var type/ecx: (payload tree type-id) = int
15700     68/push 0/imm32/right:null
15701     68/push 0/imm32/right:null
15702     68/push 0/imm32/left:unused
15703     68/push 1/imm32/value:int
15704     68/push 1/imm32/is-atom?:true
15705     68/push 0x11/imm32/alloc-id:fake:payload
15706     89/<- %ecx 4/r32/esp
15707 $test-compare-reg-with-mem:initialize-var1:
15708     # var var1/ecx: (payload var)
15709     68/push 0/imm32/register
15710     68/push 0/imm32/register
15711     68/push 0/imm32/no-stack-offset
15712     68/push 1/imm32/block-depth
15713     51/push-ecx
15714     68/push 0x11/imm32/alloc-id:fake
15715     68/push 0/imm32/name
15716     68/push 0/imm32/name
15717     68/push 0x11/imm32/alloc-id:fake:payload
15718     89/<- %ecx 4/r32/esp
15719 $test-compare-reg-with-mem:initialize-var1-name:
15720     # var1->name = "var1"
15721     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15722     (copy-array Heap "var1" %eax)
15723 $test-compare-reg-with-mem:initialize-var1-register:
15724     # var1->register = "eax"
15725     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15726     (copy-array Heap "eax" %eax)
15727 $test-compare-reg-with-mem:initialize-var2:
15728     # var var2/edx: (payload var)
15729     68/push 0/imm32/register
15730     68/push 0/imm32/register
15731     68/push 8/imm32/stack-offset
15732     68/push 1/imm32/block-depth
15733     ff 6/subop/push *(ecx+0x10)
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/<- %edx 4/r32/esp
15739 $test-compare-reg-with-mem:initialize-var2-name:
15740     # var2->name = "var2"
15741     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15742     (copy-array Heap "var2" %eax)
15743 $test-compare-reg-with-mem:initialize-inouts:
15744     # var inouts/esi: (payload stmt-var) = [var2]
15745     68/push 0/imm32/is-deref:false
15746     68/push 0/imm32/next
15747     68/push 0/imm32/next
15748     52/push-edx/var2
15749     68/push 0x11/imm32/alloc-id:fake
15750     68/push 0x11/imm32/alloc-id:fake:payload
15751     89/<- %esi 4/r32/esp
15752     # inouts = [var1, var2]
15753     68/push 0/imm32/is-deref:false
15754     56/push-esi/next
15755     68/push 0x11/imm32/alloc-id:fake
15756     51/push-ecx/var1
15757     68/push 0x11/imm32/alloc-id:fake
15758     68/push 0x11/imm32/alloc-id:fake:payload
15759     89/<- %esi 4/r32/esp
15760 $test-compare-reg-with-mem:initialize-stmt:
15761     # var stmt/esi: (addr statement)
15762     68/push 0/imm32/next
15763     68/push 0/imm32/next
15764     68/push 0/imm32/outputs
15765     68/push 0/imm32/outputs
15766     56/push-esi/inouts
15767     68/push 0x11/imm32/alloc-id:fake
15768     68/push 0/imm32/operation
15769     68/push 0/imm32/operation
15770     68/push 1/imm32/tag:stmt1
15771     89/<- %esi 4/r32/esp
15772 $test-compare-reg-with-mem:initialize-stmt-operation:
15773     # stmt->operation = "compare"
15774     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15775     (copy-array Heap "compare" %eax)
15776     # convert
15777     c7 0/subop/copy *Curr-block-depth 0/imm32
15778     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15779     (flush _test-output-buffered-file)
15780 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15786     # check output
15787     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
15788     # . epilogue
15789     89/<- %esp 5/r32/ebp
15790     5d/pop-to-ebp
15791     c3/return
15792 
15793 test-compare-mem-with-literal:
15794     #   compare var1, 0x34
15795     # =>
15796     #   81 7/subop/compare *(ebp+___) 0x34/imm32
15797     #
15798     # . prologue
15799     55/push-ebp
15800     89/<- %ebp 4/r32/esp
15801     # setup
15802     (clear-stream _test-output-stream)
15803     (clear-stream $_test-output-buffered-file->buffer)
15804 $test-compare-mem-with-literal:initialize-type:
15805     # var type/ecx: (payload tree type-id) = int
15806     68/push 0/imm32/right:null
15807     68/push 0/imm32/right:null
15808     68/push 0/imm32/left:unused
15809     68/push 1/imm32/value:int
15810     68/push 1/imm32/is-atom?:true
15811     68/push 0x11/imm32/alloc-id:fake:payload
15812     89/<- %ecx 4/r32/esp
15813 $test-compare-mem-with-literal:initialize-var1:
15814     # var var1/ecx: (payload var)
15815     68/push 0/imm32/register
15816     68/push 0/imm32/register
15817     68/push 8/imm32/stack-offset
15818     68/push 1/imm32/block-depth
15819     51/push-ecx
15820     68/push 0x11/imm32/alloc-id:fake
15821     68/push 0/imm32/name
15822     68/push 0/imm32/name
15823     68/push 0x11/imm32/alloc-id:fake:payload
15824     89/<- %ecx 4/r32/esp
15825 $test-compare-mem-with-literal:initialize-var1-name:
15826     # var1->name = "var1"
15827     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15828     (copy-array Heap "var1" %eax)
15829 $test-compare-mem-with-literal:initialize-literal-type:
15830     # var type/edx: (payload tree type-id) = literal
15831     68/push 0/imm32/right:null
15832     68/push 0/imm32/right:null
15833     68/push 0/imm32/left:unused
15834     68/push 0/imm32/value:literal
15835     68/push 1/imm32/is-atom?:true
15836     68/push 0x11/imm32/alloc-id:fake:payload
15837     89/<- %edx 4/r32/esp
15838 $test-compare-mem-with-literal:initialize-literal:
15839     # var l/edx: (payload var)
15840     68/push 0/imm32/register
15841     68/push 0/imm32/register
15842     68/push 0/imm32/no-stack-offset
15843     68/push 1/imm32/block-depth
15844     52/push-edx
15845     68/push 0x11/imm32/alloc-id:fake
15846     68/push 0/imm32/name
15847     68/push 0/imm32/name
15848     68/push 0x11/imm32/alloc-id:fake:payload
15849     89/<- %edx 4/r32/esp
15850 $test-compare-mem-with-literal:initialize-literal-value:
15851     # l->name = "0x34"
15852     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15853     (copy-array Heap "0x34" %eax)
15854 $test-compare-mem-with-literal:initialize-inouts:
15855     # var inouts/esi: (payload stmt-var) = [l]
15856     68/push 0/imm32/is-deref:false
15857     68/push 0/imm32/next
15858     68/push 0/imm32/next
15859     52/push-edx/l
15860     68/push 0x11/imm32/alloc-id:fake
15861     68/push 0x11/imm32/alloc-id:fake:payload
15862     89/<- %esi 4/r32/esp
15863     # var inouts = (handle stmt-var) = [var1, var2]
15864     68/push 0/imm32/is-deref:false
15865     56/push-esi/next
15866     68/push 0x11/imm32/alloc-id:fake
15867     51/push-ecx/var1
15868     68/push 0x11/imm32/alloc-id:fake
15869     68/push 0x11/imm32/alloc-id:fake:payload
15870     89/<- %esi 4/r32/esp
15871 $test-compare-mem-with-literal:initialize-stmt:
15872     # var stmt/esi: (addr statement)
15873     68/push 0/imm32/next
15874     68/push 0/imm32/next
15875     68/push 0/imm32/outputs
15876     68/push 0/imm32/outputs
15877     56/push-esi/inouts
15878     68/push 0x11/imm32/alloc-id:fake
15879     68/push 0/imm32/operation
15880     68/push 0/imm32/operation
15881     68/push 1/imm32/tag:stmt1
15882     89/<- %esi 4/r32/esp
15883 $test-compare-mem-with-literal:initialize-stmt-operation:
15884     # stmt->operation = "compare"
15885     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
15886     (copy-array Heap "compare" %eax)
15887     # convert
15888     c7 0/subop/copy *Curr-block-depth 0/imm32
15889     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
15890     (flush _test-output-buffered-file)
15891 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
15897     # check output
15898     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
15899     # . epilogue
15900     89/<- %esp 5/r32/ebp
15901     5d/pop-to-ebp
15902     c3/return
15903 
15904 test-compare-eax-with-literal:
15905     #   compare var1/eax 0x34
15906     # =>
15907     #   3d/compare-eax-with 0x34/imm32
15908     #
15909     # . prologue
15910     55/push-ebp
15911     89/<- %ebp 4/r32/esp
15912     # setup
15913     (clear-stream _test-output-stream)
15914     (clear-stream $_test-output-buffered-file->buffer)
15915 $test-compare-eax-with-literal:initialize-type:
15916     # var type/ecx: (payload tree type-id) = int
15917     68/push 0/imm32/right:null
15918     68/push 0/imm32/right:null
15919     68/push 0/imm32/left:unused
15920     68/push 1/imm32/value:int
15921     68/push 1/imm32/is-atom?:true
15922     68/push 0x11/imm32/alloc-id:fake:payload
15923     89/<- %ecx 4/r32/esp
15924 $test-compare-eax-with-literal:initialize-var1:
15925     # var var1/ecx: (payload var)
15926     68/push 0/imm32/register
15927     68/push 0/imm32/register
15928     68/push 0/imm32/no-stack-offset
15929     68/push 1/imm32/block-depth
15930     51/push-ecx
15931     68/push 0x11/imm32/alloc-id:fake
15932     68/push 0/imm32/name
15933     68/push 0/imm32/name
15934     68/push 0x11/imm32/alloc-id:fake:payload
15935     89/<- %ecx 4/r32/esp
15936 $test-compare-eax-with-literal:initialize-var1-name:
15937     # var1->name = "var1"
15938     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
15939     (copy-array Heap "var1" %eax)
15940 $test-compare-eax-with-literal:initialize-var1-register:
15941     # v->register = "eax"
15942     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
15943     (copy-array Heap "eax" %eax)
15944 $test-compare-eax-with-literal:initialize-literal-type:
15945     # var type/edx: (payload tree type-id) = literal
15946     68/push 0/imm32/right:null
15947     68/push 0/imm32/right:null
15948     68/push 0/imm32/left:unused
15949     68/push 0/imm32/value:literal
15950     68/push 1/imm32/is-atom?:true
15951     68/push 0x11/imm32/alloc-id:fake:payload
15952     89/<- %edx 4/r32/esp
15953 $test-compare-eax-with-literal:initialize-literal:
15954     # var l/edx: (payload var)
15955     68/push 0/imm32/register
15956     68/push 0/imm32/register
15957     68/push 0/imm32/no-stack-offset
15958     68/push 1/imm32/block-depth
15959     52/push-edx
15960     68/push 0x11/imm32/alloc-id:fake
15961     68/push 0/imm32/name
15962     68/push 0/imm32/name
15963     68/push 0x11/imm32/alloc-id:fake:payload
15964     89/<- %edx 4/r32/esp
15965 $test-compare-eax-with-literal:initialize-literal-value:
15966     # l->name = "0x34"
15967     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
15968     (copy-array Heap "0x34" %eax)
15969 $test-compare-eax-with-literal:initialize-inouts:
15970     # var inouts/esi: (payload stmt-var) = [l]
15971     68/push 0/imm32/is-deref:false
15972     68/push 0/imm32/next
15973     68/push 0/imm32/next
15974     52/push-edx/l
15975     68/push 0x11/imm32/alloc-id:fake
15976     68/push 0x11/imm32/alloc-id:fake:payload
15977     89/<- %esi 4/r32/esp
15978     # var inouts = (handle stmt-var) = [var1, var2]
15979     68/push 0/imm32/is-deref:false
15980     56/push-esi/next
15981     68/push 0x11/imm32/alloc-id:fake
15982     51/push-ecx/var1
15983     68/push 0x11/imm32/alloc-id:fake
15984     68/push 0x11/imm32/alloc-id:fake:payload
15985     89/<- %esi 4/r32/esp
15986 $test-compare-eax-with-literal:initialize-stmt:
15987     # var stmt/esi: (addr statement)
15988     68/push 0/imm32/next
15989     68/push 0/imm32/next
15990     68/push 0/imm32/outputs
15991     68/push 0/imm32/outputs
15992     56/push-esi/inouts
15993     68/push 0x11/imm32/alloc-id:fake
15994     68/push 0/imm32/operation
15995     68/push 0/imm32/operation
15996     68/push 1/imm32/tag:stmt1
15997     89/<- %esi 4/r32/esp
15998 $test-compare-eax-with-literal:initialize-stmt-operation:
15999     # stmt->operation = "compare"
16000     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16001     (copy-array Heap "compare" %eax)
16002     # convert
16003     c7 0/subop/copy *Curr-block-depth 0/imm32
16004     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16005     (flush _test-output-buffered-file)
16006 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16012     # check output
16013     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
16014     # . epilogue
16015     89/<- %esp 5/r32/ebp
16016     5d/pop-to-ebp
16017     c3/return
16018 
16019 test-compare-reg-with-literal:
16020     #   compare var1/ecx 0x34
16021     # =>
16022     #   81 7/subop/compare %ecx 0x34/imm32
16023     #
16024     # . prologue
16025     55/push-ebp
16026     89/<- %ebp 4/r32/esp
16027     # setup
16028     (clear-stream _test-output-stream)
16029     (clear-stream $_test-output-buffered-file->buffer)
16030 $test-compare-reg-with-literal:initialize-type:
16031     # var type/ecx: (payload tree type-id) = int
16032     68/push 0/imm32/right:null
16033     68/push 0/imm32/right:null
16034     68/push 0/imm32/left:unused
16035     68/push 1/imm32/value:int
16036     68/push 1/imm32/is-atom?:true
16037     68/push 0x11/imm32/alloc-id:fake:payload
16038     89/<- %ecx 4/r32/esp
16039 $test-compare-reg-with-literal:initialize-var1:
16040     # var var1/ecx: (payload var)
16041     68/push 0/imm32/register
16042     68/push 0/imm32/register
16043     68/push 0/imm32/no-stack-offset
16044     68/push 1/imm32/block-depth
16045     51/push-ecx
16046     68/push 0x11/imm32/alloc-id:fake
16047     68/push 0/imm32/name
16048     68/push 0/imm32/name
16049     68/push 0x11/imm32/alloc-id:fake:payload
16050     89/<- %ecx 4/r32/esp
16051 $test-compare-reg-with-literal:initialize-var1-name:
16052     # var1->name = "var1"
16053     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16054     (copy-array Heap "var1" %eax)
16055 $test-compare-reg-with-literal:initialize-var1-register:
16056     # v->register = "ecx"
16057     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
16058     (copy-array Heap "ecx" %eax)
16059 $test-compare-reg-with-literal:initialize-literal-type:
16060     # var type/edx: (payload tree type-id) = literal
16061     68/push 0/imm32/right:null
16062     68/push 0/imm32/right:null
16063     68/push 0/imm32/left:unused
16064     68/push 0/imm32/value:literal
16065     68/push 1/imm32/is-atom?:true
16066     68/push 0x11/imm32/alloc-id:fake:payload
16067     89/<- %edx 4/r32/esp
16068 $test-compare-reg-with-literal:initialize-literal:
16069     # var l/edx: (payload var)
16070     68/push 0/imm32/register
16071     68/push 0/imm32/register
16072     68/push 0/imm32/no-stack-offset
16073     68/push 1/imm32/block-depth
16074     52/push-edx
16075     68/push 0x11/imm32/alloc-id:fake
16076     68/push 0/imm32/name
16077     68/push 0/imm32/name
16078     68/push 0x11/imm32/alloc-id:fake:payload
16079     89/<- %edx 4/r32/esp
16080 $test-compare-reg-with-literal:initialize-literal-value:
16081     # l->name = "0x34"
16082     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
16083     (copy-array Heap "0x34" %eax)
16084 $test-compare-reg-with-literal:initialize-inouts:
16085     # var inouts/esi: (payload stmt-var) = [l]
16086     68/push 0/imm32/is-deref:false
16087     68/push 0/imm32/next
16088     68/push 0/imm32/next
16089     52/push-edx/l
16090     68/push 0x11/imm32/alloc-id:fake
16091     68/push 0x11/imm32/alloc-id:fake:payload
16092     89/<- %esi 4/r32/esp
16093     # var inouts = (handle stmt-var) = [var1, var2]
16094     68/push 0/imm32/is-deref:false
16095     56/push-esi/next
16096     68/push 0x11/imm32/alloc-id:fake
16097     51/push-ecx/var1
16098     68/push 0x11/imm32/alloc-id:fake
16099     68/push 0x11/imm32/alloc-id:fake:payload
16100     89/<- %esi 4/r32/esp
16101 $test-compare-reg-with-literal:initialize-stmt:
16102     # var stmt/esi: (addr statement)
16103     68/push 0/imm32/next
16104     68/push 0/imm32/next
16105     68/push 0/imm32/outputs
16106     68/push 0/imm32/outputs
16107     56/push-esi/inouts
16108     68/push 0x11/imm32/alloc-id:fake
16109     68/push 0/imm32/operation
16110     68/push 0/imm32/operation
16111     68/push 1/imm32/tag:stmt1
16112     89/<- %esi 4/r32/esp
16113 $test-compare-reg-with-literal:initialize-stmt-operation:
16114     # stmt->operation = "compare"
16115     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16116     (copy-array Heap "compare" %eax)
16117     # convert
16118     c7 0/subop/copy *Curr-block-depth 0/imm32
16119     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
16120     (flush _test-output-buffered-file)
16121 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16127     # check output
16128     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
16129     # . epilogue
16130     89/<- %esp 5/r32/ebp
16131     5d/pop-to-ebp
16132     c3/return
16133 
16134 test-emit-subx-stmt-function-call:
16135     # Call a function on a variable on the stack.
16136     #   f foo
16137     # =>
16138     #   (f *(ebp-8))
16139     # (Changing the function name supports overloading in general, but here it
16140     # just serves to help disambiguate things.)
16141     #
16142     # There's a variable on the var stack as follows:
16143     #   name: 'foo'
16144     #   type: int
16145     #   stack-offset: -8
16146     #
16147     # There's nothing in primitives.
16148     #
16149     # We don't perform any checking here on the type of 'f'.
16150     #
16151     # . prologue
16152     55/push-ebp
16153     89/<- %ebp 4/r32/esp
16154     # setup
16155     (clear-stream _test-output-stream)
16156     (clear-stream $_test-output-buffered-file->buffer)
16157 $test-emit-subx-function-call:initialize-type:
16158     # var type/ecx: (payload tree type-id) = int
16159     68/push 0/imm32/right:null
16160     68/push 0/imm32/right:null
16161     68/push 0/imm32/left:unused
16162     68/push 1/imm32/value:int
16163     68/push 1/imm32/is-atom?:true
16164     68/push 0x11/imm32/alloc-id:fake:payload
16165     89/<- %ecx 4/r32/esp
16166 $test-emit-subx-function-call:initialize-var:
16167     # var var-foo/ecx: (payload var) = var(type)
16168     68/push 0/imm32/no-register
16169     68/push 0/imm32/no-register
16170     68/push -8/imm32/stack-offset
16171     68/push 1/imm32/block-depth
16172     51/push-ecx/type
16173     68/push 0x11/imm32/alloc-id:fake
16174     68/push 0/imm32/name
16175     68/push 0/imm32/name
16176     68/push 0x11/imm32/alloc-id:fake:payload
16177     89/<- %ecx 4/r32/esp
16178 $test-emit-subx-function-call:initialize-var-name:
16179     # var-foo->name = "foo"
16180     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16181     (copy-array Heap "foo" %eax)
16182 $test-emit-subx-function-call:initialize-stmt-var:
16183     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
16184     68/push 0/imm32/is-deref:false
16185     68/push 0/imm32/next
16186     68/push 0/imm32/next
16187     51/push-ecx/var-foo
16188     68/push 0x11/imm32/alloc-id:fake
16189     68/push 0x11/imm32/alloc-id:fake:payload
16190     89/<- %ebx 4/r32/esp
16191 $test-emit-subx-function-call:initialize-stmt:
16192     # var stmt/esi: (addr statement)
16193     68/push 0/imm32/no-outputs
16194     68/push 0/imm32/no-outputs
16195     53/push-ebx/inouts
16196     68/push 0x11/imm32/alloc-id:fake
16197     68/push 0/imm32/operation
16198     68/push 0/imm32/operation
16199     68/push 1/imm32/tag
16200     89/<- %esi 4/r32/esp
16201 $test-emit-subx-function-call:initialize-stmt-operation:
16202     # stmt->operation = "f"
16203     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16204     (copy-array Heap "f" %eax)
16205     # convert
16206     c7 0/subop/copy *Curr-block-depth 0/imm32
16207     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
16208     (flush _test-output-buffered-file)
16209 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16215     # check output
16216     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
16217     # . epilogue
16218     89/<- %esp 5/r32/ebp
16219     5d/pop-to-ebp
16220     c3/return
16221 
16222 test-emit-subx-stmt-function-call-with-literal-arg:
16223     # Call a function on a literal.
16224     #   f 0x34
16225     # =>
16226     #   (f2 0x34)
16227     #
16228     # . prologue
16229     55/push-ebp
16230     89/<- %ebp 4/r32/esp
16231     # setup
16232     (clear-stream _test-output-stream)
16233     (clear-stream $_test-output-buffered-file->buffer)
16234 $test-emit-subx-function-call-with-literal-arg:initialize-type:
16235     # var type/ecx: (payload tree type-id) = int
16236     68/push 0/imm32/right:null
16237     68/push 0/imm32/right:null
16238     68/push 0/imm32/left:unused
16239     68/push 0/imm32/value:literal
16240     68/push 1/imm32/is-atom?:true
16241     68/push 0x11/imm32/alloc-id:fake:payload
16242     89/<- %ecx 4/r32/esp
16243 $test-emit-subx-function-call-with-literal-arg:initialize-var:
16244     # var var-foo/ecx: (payload var) = var(lit)
16245     68/push 0/imm32/no-register
16246     68/push 0/imm32/no-register
16247     68/push 0/imm32/no-stack-offset
16248     68/push 1/imm32/block-depth
16249     51/push-ecx/type
16250     68/push 0x11/imm32/alloc-id:fake
16251     68/push 0/imm32/name
16252     68/push 0/imm32/name
16253     68/push 0x11/imm32/alloc-id:fake:payload
16254     89/<- %ecx 4/r32/esp
16255 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
16256     # var-foo->name = "0x34"
16257     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
16258     (copy-array Heap "0x34" %eax)
16259 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
16260     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
16261     68/push 0/imm32/is-deref:false
16262     68/push 0/imm32/next
16263     68/push 0/imm32/next
16264     51/push-ecx/var-foo
16265     68/push 0x11/imm32/alloc-id:fake
16266     68/push 0x11/imm32/alloc-id:fake:payload
16267     89/<- %ebx 4/r32/esp
16268 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
16269     # var stmt/esi: (addr statement)
16270     68/push 0/imm32/no-outputs
16271     68/push 0/imm32/no-outputs
16272     53/push-ebx/inouts
16273     68/push 0x11/imm32/alloc-id:fake
16274     68/push 0/imm32/operation
16275     68/push 0/imm32/operation
16276     68/push 1/imm32/tag
16277     89/<- %esi 4/r32/esp
16278 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
16279     # stmt->operation = "f"
16280     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
16281     (copy-array Heap "f" %eax)
16282     # convert
16283     c7 0/subop/copy *Curr-block-depth 0/imm32
16284     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
16285     (flush _test-output-buffered-file)
16286 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
16292     # check output
16293     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
16294     # . epilogue
16295     89/<- %esp 5/r32/ebp
16296     5d/pop-to-ebp
16297     c3/return
16298 
16299 emit-indent:  # out: (addr buffered-file), n: int
16300     # . prologue
16301     55/push-ebp
16302     89/<- %ebp 4/r32/esp
16303     # . save registers
16304     50/push-eax
16305     # var i/eax: int = n
16306     8b/-> *(ebp+0xc) 0/r32/eax
16307     {
16308       # if (i <= 0) break
16309       3d/compare-eax-with 0/imm32
16310       7e/jump-if-<= break/disp8
16311       (write-buffered *(ebp+8) "  ")
16312       48/decrement-eax
16313       eb/jump loop/disp8
16314     }
16315 $emit-indent:end:
16316     # . restore registers
16317     58/pop-to-eax
16318     # . epilogue
16319     89/<- %esp 5/r32/ebp
16320     5d/pop-to-ebp
16321     c3/return
16322 
16323 emit-subx-prologue:  # out: (addr buffered-file)
16324     # . prologue
16325     55/push-ebp
16326     89/<- %ebp 4/r32/esp
16327     #
16328     (write-buffered *(ebp+8) "  # . prologue\n")
16329     (write-buffered *(ebp+8) "  55/push-ebp\n")
16330     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
16331 $emit-subx-prologue:end:
16332     # . epilogue
16333     89/<- %esp 5/r32/ebp
16334     5d/pop-to-ebp
16335     c3/return
16336 
16337 emit-subx-epilogue:  # out: (addr buffered-file)
16338     # . prologue
16339     55/push-ebp
16340     89/<- %ebp 4/r32/esp
16341     #
16342     (write-buffered *(ebp+8) "  # . epilogue\n")
16343     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
16344     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
16345     (write-buffered *(ebp+8) "  c3/return\n")
16346 $emit-subx-epilogue:end:
16347     # . epilogue
16348     89/<- %esp 5/r32/ebp
16349     5d/pop-to-ebp
16350     c3/return