https://github.com/akkartik/mu/blob/master/apps/mu.subx
    1 # The Mu computer's level-2 language, also called Mu.
    2 # http://akkartik.name/post/mu-2019-2
    3 #
    4 # To run:
    5 #   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
    6 #   $ ./a.elf < prog.mu > prog.elf
    7 
    8 # == Goals
    9 # 1. Be memory safe. It should be impossible to corrupt the heap, or to create
   10 # a bad pointer. (Requires strong type safety.)
   11 # 2. Do as little as possible to achieve goal 1. The translator should be
   12 # implementable in machine code.
   13 #   - minimize impedance mismatch between source language and SubX target
   14 #     (e.g. programmer manages registers manually)
   15 #   - checks over syntax
   16 #     (e.g. programmer's register allocation is checked)
   17 #   - runtime checks to avoid complex static analysis
   18 #     (e.g. array indexing always checks bounds)
   19 
   20 # == Language description
   21 # A program is a sequence of function and type definitions.
   22 #
   23 # Function example:
   24 #   fn foo n: int -> result/eax: int {
   25 #     ...
   26 #   }
   27 #
   28 # Functions consist of a name, optional inputs, optional outputs and a block.
   29 #
   30 # Function inputs and outputs are variables. All variables have a type and
   31 # storage specifier. They can be placed either in memory (on the stack) or in
   32 # one of 6 named registers.
   33 #   eax ecx edx ebx esi edi
   34 # Variables in registers must be primitive 32-bit types.
   35 # Variables not explicitly placed in a register are on the stack.
   36 #
   37 # Function inputs are always passed in memory (on the stack), while outputs
   38 # are always returned in registers.
   39 #
   40 # Blocks mostly consist of statements.
   41 #
   42 # Statements mostly consist of a name, optional inputs and optional outputs.
   43 #
   44 # Statement inputs are variables or literals. Variables need to specify type
   45 # (and storage) the first time they're mentioned but not later.
   46 #
   47 # Statement outputs, like function outputs, must be variables in registers.
   48 #
   49 # Statement names must be either primitives or user-defined functions.
   50 #
   51 # Primitives can write to any register.
   52 # User-defined functions only write to hard-coded registers. Outputs of each
   53 # call must have the same registers as in the function definition.
   54 #
   55 # There are some other statement types:
   56 #   - blocks. Multiple statements surrounded by '{...}' and optionally
   57 #     prefixed with a label name and ':'
   58 #       - {
   59 #           ...
   60 #         }
   61 #       - foo: {
   62 #           ...
   63 #         }
   64 #
   65 #   - variable definitions on the stack. E.g.:
   66 #       - var foo: int
   67 #       - var bar: (array int 3)
   68 #     There's no initializer; variables are automatically initialized.
   69 #     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
   70 #
   71 #   - variables definitions in a register. E.g.:
   72 #       - var foo/eax: int <- add bar 1
   73 #     The initializer is mandatory and must be a valid instruction that writes
   74 #     a single output to the right register. In practice registers will
   75 #     usually be either initialized by primitives or copied from eax.
   76 #       - var eax: int <- foo bar quux
   77 #         var floo/ecx: int <- copy eax
   78 #
   79 # Still todo:
   80 #   global variables
   81 #   union types
   82 #
   83 # Formal types:
   84 #   A program is a linked list of functions
   85 #   A function contains:
   86 #     name: (handle array byte)
   87 #     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
   88 #       data: (handle var)
   89 #       next: (handle list)
   90 #     outputs: linked list of vars
   91 #       data: (handle var)
   92 #       next: (handle list)
   93 #     body: (handle block)
   94 #   A var-type contains:
   95 #     name: (handle array byte)
   96 #     type: (handle type-tree)
   97 #
   98 #   A statement can be:
   99 #     tag 0: a block
  100 #     tag 1: a simple statement (stmt1)
  101 #     tag 2: a variable defined on the stack
  102 #     tag 3: a variable defined in a register
  103 #
  104 #   A block contains:
  105 #     tag: 0
  106 #     statements: (handle list stmt)
  107 #     name: (handle array byte) -- starting with '$'
  108 #
  109 #   A regular statement contains:
  110 #     tag: 1
  111 #     operation: (handle array byte)
  112 #     inouts: (handle list operand)
  113 #     outputs: (handle list var)
  114 #
  115 #   A variable defined on the stack contains:
  116 #     tag: 2
  117 #     name: (handle array byte)
  118 #     type: (handle type-tree)
  119 #
  120 #   A variable defined in a register contains:
  121 #     tag: 3
  122 #     name: (handle array byte)
  123 #     type: (handle type-tree)
  124 #     reg: (handle array byte)
  125 
  126 # == Translation: managing the stack
  127 # Now that we know what the language looks like in the large, let's think
  128 # about how translation happens from the bottom up. One crucial piece of the
  129 # puzzle is how Mu will clean up variables defined on the stack for you.
  130 #
  131 # Assume that we maintain a 'functions' list while parsing source code. And a
  132 # 'primitives' list is a global constant. Both these contain enough information
  133 # to perform type-checking on function calls or primitive statements, respectively.
  134 #
  135 # Defining variables pushes them on a stack with the current block depth and
  136 # enough information about their location (stack offset or register).
  137 # Starting a block increments the current block id.
  138 # Each statement now has enough information to emit code for it.
  139 # Ending a block is where the magic happens:
  140 #   pop all variables at the current block depth
  141 #   emit code to restore all register variables introduced at the current depth
  142 #   emit code to clean up all stack variables at the current depth (just increment esp)
  143 #   decrement the current block depth
  144 #
  145 # Formal types:
  146 #   live-vars: stack of vars
  147 #   var:
  148 #     name: (handle array byte)
  149 #     type: (handle type-tree)
  150 #     block: int
  151 #     stack-offset: int  (added to ebp)
  152 #     register: (handle array byte)
  153 #       either usual register names
  154 #       or '*' to indicate any register
  155 #   At most one of stack-offset or register-index must be non-zero.
  156 #   A register of '*' designates a variable _template_. Only legal in formal
  157 #   parameters for primitives.
  158 
  159 # == Translating a single function call
  160 # This one's easy. Assuming we've already checked things, we just drop the
  161 # outputs (which use hard-coded registers) and emit inputs in a standard format.
  162 #
  163 # out1, out2, out3, ... <- name inout1, inout2, inout3, ...
  164 # =>
  165 # (name inout1 inout2 inout3)
  166 #
  167 # Formal types:
  168 #   functions: linked list of info
  169 #     name: (handle array byte)
  170 #     inouts: linked list of vars
  171 #     outputs: linked list of vars
  172 #     body: block (linked list of statements)
  173 
  174 # == Translating a single primitive instruction
  175 # A second crucial piece of the puzzle is how Mu converts fairly regular
  176 # primitives with their uniform syntax to SubX instructions with their gnarly
  177 # x86 details.
  178 #
  179 # Mu instructions have inputs and outputs. Primitives can have up to 2 of
  180 # them.
  181 # SubX instructions have rm32 and r32 operands.
  182 # The translation between them covers almost all the possibilities.
  183 #   Instructions with 1 inout may turn into ones with 1 rm32
  184 #     (e.g. incrementing a var on the stack)
  185 #   Instructions with 1 output may turn into ones with 1 rm32
  186 #     (e.g. incrementing a var in a register)
  187 #   1 inout and 1 output may turn into 1 rm32 and 1 r32
  188 #     (e.g. adding a var to a reg)
  189 #   2 inouts may turn into 1 rm32 and 1 r32
  190 #     (e.g. adding a reg to a var)
  191 #   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
  192 #     (e.g. adding a constant to a var)
  193 #   1 output and 1 literal may turn into 1 rm32 and 1 imm32
  194 #     (e.g. adding a constant to a reg)
  195 #   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
  196 #     (special-case: divide edx:eax by a var or reg)
  197 # Observations:
  198 #   We always emit rm32. It may be the first inout or the first output.
  199 #   We may emit r32 or imm32 or neither.
  200 #   When we emit r32 it may come from first inout or second inout or first output.
  201 #
  202 # Accordingly, the formal data structure for a primitive looks like this:
  203 #   primitives: linked list of info
  204 #     name: (handle array byte)
  205 #     mu-inouts: linked list of vars to check
  206 #     mu-outputs: linked list of vars to check; at most a singleton
  207 #     subx-name: (handle array byte)
  208 #     subx-rm32: enum arg-location
  209 #     subx-r32: enum arg-location
  210 #     subx-imm32: enum arg-location
  211 #     subx-disp32: enum arg-location
  212 #     output-is-write-only: boolean
  213 #   arg-location: enum
  214 #     0 means none
  215 #     1 means first inout
  216 #     2 means second inout
  217 #     3 means first output
  218 
  219 # == Translating a block
  220 # Emit block name if necessary
  221 # Emit '{'
  222 # When you encounter a statement, emit it as above
  223 # When you encounter a variable declaration
  224 #   emit any code needed for it (bzeros)
  225 #   push it on the var stack
  226 #   update register dict if necessary
  227 # When you encounter '}'
  228 #   While popping variables off the var stack until block id changes
  229 #     Emit code needed to clean up the stack
  230 #       either increment esp
  231 #       or pop into appropriate register
  232 
  233 # The rest is straightforward.
  234 
  235 == data
  236 
  237 Program:
  238 _Program-functions:  # (handle function)
  239   0/imm32
  240 _Program-functions->payload:
  241   0/imm32
  242 _Program-types:  # (handle typeinfo)
  243   0/imm32
  244 _Program-types->payload:
  245   0/imm32
  246 _Program-signatures:  # (handle function)
  247   0/imm32
  248 _Program-signatures->payload:
  249   0/imm32
  250 
  251 # Some constants for simulating the data structures described above.
  252 # Many constants here come with a type in a comment.
  253 #
  254 # Sometimes the type is of the value at that offset for the given type. For
  255 # example, if you start at a function record and move forward Function-inouts
  256 # bytes, you'll find a (handle list var).
  257 #
  258 # At other times, the type is of the constant itself. For example, the type of
  259 # the constant Function-size is (addr int). To get the size of a function,
  260 # look in *Function-size.
  261 
  262 Function-name:  # (handle array byte)
  263   0/imm32
  264 Function-inouts:  # (handle list var)
  265   8/imm32
  266 Function-outputs:  # (handle list var)
  267   0x10/imm32
  268 Function-body:  # (handle block)
  269   0x18/imm32
  270 Function-next:  # (handle function)
  271   0x20/imm32
  272 Function-size:  # (addr int)
  273   0x28/imm32/40
  274 
  275 Primitive-name:  # (handle array byte)
  276   0/imm32
  277 Primitive-inouts:  # (handle list var)
  278   8/imm32
  279 Primitive-outputs:  # (handle list var)
  280   0x10/imm32
  281 Primitive-subx-name:  # (handle array byte)
  282   0x18/imm32
  283 Primitive-subx-rm32:  # enum arg-location
  284   0x20/imm32
  285 Primitive-subx-r32:  # enum arg-location
  286   0x24/imm32
  287 Primitive-subx-imm32:  # enum arg-location
  288   0x28/imm32
  289 Primitive-subx-disp32:  # enum arg-location  -- only for branches
  290   0x2c/imm32
  291 Primitive-output-is-write-only:  # boolean
  292   0x30/imm32
  293 Primitive-next:  # (handle function)
  294   0x34/imm32
  295 Primitive-size:  # (addr int)
  296   0x3c/imm32/60
  297 
  298 Stmt-tag:  # int
  299   0/imm32
  300 
  301 Block-stmts:  # (handle list stmt)
  302   4/imm32
  303 Block-var:  # (handle var)
  304   0xc/imm32
  305 
  306 Stmt1-operation:  # (handle array byte)
  307   4/imm32
  308 Stmt1-inouts:  # (handle stmt-var)
  309   0xc/imm32
  310 Stmt1-outputs:  # (handle stmt-var)
  311   0x14/imm32
  312 
  313 Vardef-var:  # (handle var)
  314   4/imm32
  315 
  316 Regvardef-operation:  # (handle array byte)
  317   4/imm32
  318 Regvardef-inouts:  # (handle stmt-var)
  319   0xc/imm32
  320 Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  321   0x14/imm32
  322 
  323 Stmt-size:  # (addr int)
  324   0x1c/imm32
  325 
  326 Var-name:  # (handle array byte)
  327   0/imm32
  328 Var-type:  # (handle type-tree)
  329   8/imm32
  330 Var-block-depth:  # int -- not available until code-generation time
  331   0x10/imm32
  332 Var-offset:  # int -- not available until code-generation time
  333   0x14/imm32
  334 Var-register:  # (handle array byte) -- name of a register
  335   0x18/imm32
  336 Var-size:  # (addr int)
  337   0x20/imm32
  338 
  339 List-value:  # (handle _)
  340   0/imm32
  341 List-next:  # (handle list _)
  342   8/imm32
  343 List-size:  # (addr int)
  344   0x10/imm32
  345 
  346 # A stmt-var is like a list of vars with call-site specific metadata
  347 Stmt-var-value:  # (handle var)
  348   0/imm32
  349 Stmt-var-next:  # (handle stmt-var)
  350   8/imm32
  351 Stmt-var-is-deref:  # boolean
  352   0x10/imm32
  353 Stmt-var-size:  # (addr int)
  354   0x14/imm32
  355 
  356 # A live-var is a var augmented with information needed for tracking live
  357 # variables.
  358 Live-var-value:  # (handle var)
  359   0/imm32
  360 Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  361   8/imm32
  362 Live-var-size:  # (addr int)
  363   0xc/imm32
  364 
  365 # Types are expressed as trees (s-expressions) of type-ids (ints).
  366 
  367 Type-tree-is-atom:  # boolean
  368   0/imm32
  369 # if left-is-atom?
  370 Type-tree-value:  # type-id
  371   4/imm32
  372 Type-tree-value-size:  # int (for static data structure sizes)
  373   8/imm32
  374 # unless left-is-atom?
  375 Type-tree-left:  # (addr type-tree)
  376   4/imm32
  377 Type-tree-right:  # (addr type-tree)
  378   0xc/imm32
  379 #
  380 Type-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   0/imm32/write  # initialized later from Primitive-type-ids
  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  # 9 reserved for array-capacity; value is in Type-tree-size
  402            # Not to be used directly, so we don't include a name here.
  403                   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   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  409   0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  410 
  411 Primitive-type-ids:  # (addr int)
  412   0x24
  413 
  414 # == Type definitions
  415 # Program->types contains some typeinfo for each type definition.
  416 # Types contain vars with types, but can't specify registers.
  417 Typeinfo-id:  # type-id
  418   0/imm32
  419 Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  420   4/imm32
  421 # Total size must be >= 0
  422 # During parsing it may take on two additional values:
  423 #   -2: not yet initialized
  424 #   -1: in process of being computed
  425 # See populate-mu-type-sizes for details.
  426 Typeinfo-total-size-in-bytes:  # int
  427   0xc/imm32
  428 Typeinfo-next:  # (handle typeinfo)
  429   0x10/imm32
  430 Typeinfo-size:  # (addr int)
  431   0x18/imm32
  432 
  433 # Each entry in the typeinfo->fields table has a pointer to a string and a
  434 # pointer to a typeinfo-entry.
  435 Typeinfo-fields-row-size:  # (addr int)
  436   0x10/imm32
  437 
  438 # typeinfo-entry objects have information about a field in a single record type
  439 #
  440 # each field of a type is represented using two var's:
  441 #   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
  442 #   2. the output var: a constant containing the byte offset; convenient for code-generation
  443 # computing the output happens after parsing; in the meantime we preserve the
  444 # order of fields in the 'index' field.
  445 Typeinfo-entry-input-var:  # (handle var)
  446   0/imm32
  447 Typeinfo-entry-index:  # int
  448   8/imm32
  449 Typeinfo-entry-output-var:  # (handle var)
  450   0xc/imm32
  451 Typeinfo-entry-size:  # (addr int)
  452   0x14/imm32
  453 
  454 == code
  455 
  456 Entry:
  457     # . prologue
  458     89/<- %ebp 4/r32/esp
  459     (new-segment *Heap-size Heap)
  460     # if (argv[1] == "test') run-tests()
  461     {
  462       # if (argc <= 1) break
  463       81 7/subop/compare *ebp 1/imm32
  464       7e/jump-if-<= break/disp8
  465       # if (argv[1] != "test") break
  466       (kernel-string-equal? *(ebp+8) "test")  # => eax
  467       3d/compare-eax-and 0/imm32/false
  468       74/jump-if-= break/disp8
  469       #
  470       (run-tests)
  471       # syscall(exit, *Num-test-failures)
  472       8b/-> *Num-test-failures 3/r32/ebx
  473       eb/jump $mu-main:end/disp8
  474     }
  475     # otherwise convert Stdin
  476     (convert-mu Stdin Stdout Stderr 0)
  477     (flush Stdout)
  478     # syscall(exit, 0)
  479     bb/copy-to-ebx 0/imm32
  480 $mu-main:end:
  481     e8/call syscall_exit/disp32
  482 
  483 convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
  484     # . prologue
  485     55/push-ebp
  486     89/<- %ebp 4/r32/esp
  487     # . save registers
  488     50/push-eax
  489     # initialize global data structures
  490     c7 0/subop/copy *Next-block-index 1/imm32
  491     8b/-> *Primitive-type-ids 0/r32/eax
  492     89/<- *Type-id 0/r32/eax  # stream-write
  493     c7 0/subop/copy *_Program-functions 0/imm32
  494     c7 0/subop/copy *_Program-functions->payload 0/imm32
  495     c7 0/subop/copy *_Program-types 0/imm32
  496     c7 0/subop/copy *_Program-types->payload 0/imm32
  497     #
  498     (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
  499     (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
  500 #?     (dump-typeinfos "=== typeinfos\n")
  501     (check-mu-types *(ebp+0x10) *(ebp+0x14))
  502     (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
  503 $convert-mu:end:
  504     # . restore registers
  505     58/pop-to-eax
  506     # . epilogue
  507     89/<- %esp 5/r32/ebp
  508     5d/pop-to-ebp
  509     c3/return
  510 
  511 test-convert-empty-input:
  512     # empty input => empty output
  513     # . prologue
  514     55/push-ebp
  515     89/<- %ebp 4/r32/esp
  516     # setup
  517     (clear-stream _test-input-stream)
  518     (clear-stream $_test-input-buffered-file->buffer)
  519     (clear-stream _test-output-stream)
  520     (clear-stream $_test-output-buffered-file->buffer)
  521     #
  522     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  523     (flush _test-output-buffered-file)
  524     (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
  525     # . epilogue
  526     89/<- %esp 5/r32/ebp
  527     5d/pop-to-ebp
  528     c3/return
  529 
  530 test-convert-function-skeleton:
  531     # . prologue
  532     55/push-ebp
  533     89/<- %ebp 4/r32/esp
  534     # setup
  535     (clear-stream _test-input-stream)
  536     (clear-stream $_test-input-buffered-file->buffer)
  537     (clear-stream _test-output-stream)
  538     (clear-stream $_test-output-buffered-file->buffer)
  539     #
  540     (write _test-input-stream "fn foo {\n")
  541     (write _test-input-stream "}\n")
  542     # convert
  543     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  544     (flush _test-output-buffered-file)
  545 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  551     # check output
  552     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
  553     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
  554     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
  555     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
  556     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
  557     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
  558     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
  559     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
  560     # . epilogue
  561     89/<- %esp 5/r32/ebp
  562     5d/pop-to-ebp
  563     c3/return
  564 
  565 test-convert-multiple-function-skeletons:
  566     # . prologue
  567     55/push-ebp
  568     89/<- %ebp 4/r32/esp
  569     # setup
  570     (clear-stream _test-input-stream)
  571     (clear-stream $_test-input-buffered-file->buffer)
  572     (clear-stream _test-output-stream)
  573     (clear-stream $_test-output-buffered-file->buffer)
  574     #
  575     (write _test-input-stream "fn foo {\n")
  576     (write _test-input-stream "}\n")
  577     (write _test-input-stream "fn bar {\n")
  578     (write _test-input-stream "}\n")
  579     # convert
  580     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  581     (flush _test-output-buffered-file)
  582 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  588     # check first function
  589     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
  590     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
  591     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
  592     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
  593     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
  594     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
  595     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
  596     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
  597     # check second function
  598     (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
  599     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
  600     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
  601     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
  602     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
  603     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
  604     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
  605     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
  606     # . epilogue
  607     89/<- %esp 5/r32/ebp
  608     5d/pop-to-ebp
  609     c3/return
  610 
  611 test-convert-function-with-arg:
  612     # . prologue
  613     55/push-ebp
  614     89/<- %ebp 4/r32/esp
  615     # setup
  616     (clear-stream _test-input-stream)
  617     (clear-stream $_test-input-buffered-file->buffer)
  618     (clear-stream _test-output-stream)
  619     (clear-stream $_test-output-buffered-file->buffer)
  620     #
  621     (write _test-input-stream "fn foo n: int {\n")
  622     (write _test-input-stream "}\n")
  623     # convert
  624     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  625     (flush _test-output-buffered-file)
  626 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  632     # check output
  633     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
  634     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
  635     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
  636     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
  637     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
  638     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
  639     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
  640     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
  641     # . epilogue
  642     89/<- %esp 5/r32/ebp
  643     5d/pop-to-ebp
  644     c3/return
  645 
  646 test-convert-function-with-arg-and-body:
  647     # . prologue
  648     55/push-ebp
  649     89/<- %ebp 4/r32/esp
  650     # setup
  651     (clear-stream _test-input-stream)
  652     (clear-stream $_test-input-buffered-file->buffer)
  653     (clear-stream _test-output-stream)
  654     (clear-stream $_test-output-buffered-file->buffer)
  655     #
  656     (write _test-input-stream "fn foo n: int {\n")
  657     (write _test-input-stream "  increment n\n")
  658     (write _test-input-stream "}\n")
  659     # convert
  660     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  661     (flush _test-output-buffered-file)
  662 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  668     # check output
  669     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
  670     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
  671     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
  672     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
  673     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
  674     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
  675     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
  676     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
  677     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
  678     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
  679     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
  680     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
  681     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
  682     # . epilogue
  683     89/<- %esp 5/r32/ebp
  684     5d/pop-to-ebp
  685     c3/return
  686 
  687 test-convert-function-distinguishes-args:
  688     # . prologue
  689     55/push-ebp
  690     89/<- %ebp 4/r32/esp
  691     # setup
  692     (clear-stream _test-input-stream)
  693     (clear-stream $_test-input-buffered-file->buffer)
  694     (clear-stream _test-output-stream)
  695     (clear-stream $_test-output-buffered-file->buffer)
  696     #
  697     (write _test-input-stream "fn foo a: int, b: int {\n")
  698     (write _test-input-stream "  increment b\n")
  699     (write _test-input-stream "}\n")
  700     # convert
  701     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  702     (flush _test-output-buffered-file)
  703 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  709     # check output
  710     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
  711     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
  712     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
  713     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
  714     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
  715     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
  716     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
  717     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
  718     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
  719     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
  720     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
  721     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
  722     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
  723     # . epilogue
  724     89/<- %esp 5/r32/ebp
  725     5d/pop-to-ebp
  726     c3/return
  727 
  728 test-convert-function-returns-result:
  729     # . prologue
  730     55/push-ebp
  731     89/<- %ebp 4/r32/esp
  732     # setup
  733     (clear-stream _test-input-stream)
  734     (clear-stream $_test-input-buffered-file->buffer)
  735     (clear-stream _test-output-stream)
  736     (clear-stream $_test-output-buffered-file->buffer)
  737     #
  738     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  739     (write _test-input-stream "  result <- copy a\n")
  740     (write _test-input-stream "  result <- increment\n")
  741     (write _test-input-stream "}\n")
  742     # convert
  743     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  744     (flush _test-output-buffered-file)
  745 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  751     # check output
  752     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
  753     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
  754     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
  755     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
  756     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
  757     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
  758     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
  759     (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
  760     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
  761     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
  762     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
  763     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
  764     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
  765     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
  766     # . epilogue
  767     89/<- %esp 5/r32/ebp
  768     5d/pop-to-ebp
  769     c3/return
  770 
  771 test-convert-function-with-literal-arg:
  772     # . prologue
  773     55/push-ebp
  774     89/<- %ebp 4/r32/esp
  775     # setup
  776     (clear-stream _test-input-stream)
  777     (clear-stream $_test-input-buffered-file->buffer)
  778     (clear-stream _test-output-stream)
  779     (clear-stream $_test-output-buffered-file->buffer)
  780     #
  781     (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
  782     (write _test-input-stream "  result <- copy a\n")
  783     (write _test-input-stream "  result <- add 1\n")
  784     (write _test-input-stream "}\n")
  785     # convert
  786     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  787     (flush _test-output-buffered-file)
  788 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  794     # check output
  795     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
  796     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
  797     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
  798     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
  799     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
  800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
  801     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
  802     (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
  803     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
  804     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
  805     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
  806     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
  807     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
  808     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
  809     # . epilogue
  810     89/<- %esp 5/r32/ebp
  811     5d/pop-to-ebp
  812     c3/return
  813 
  814 test-convert-function-with-literal-arg-2:
  815     # . prologue
  816     55/push-ebp
  817     89/<- %ebp 4/r32/esp
  818     # setup
  819     (clear-stream _test-input-stream)
  820     (clear-stream $_test-input-buffered-file->buffer)
  821     (clear-stream _test-output-stream)
  822     (clear-stream $_test-output-buffered-file->buffer)
  823     #
  824     (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
  825     (write _test-input-stream "  result <- copy a\n")
  826     (write _test-input-stream "  result <- add 1\n")
  827     (write _test-input-stream "}\n")
  828     # convert
  829     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  830     (flush _test-output-buffered-file)
  831 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  837     # check output
  838     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
  839     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
  840     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
  841     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
  842     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
  843     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
  844     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
  845     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
  846     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
  847     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
  848     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
  849     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
  850     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
  851     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
  852     # . epilogue
  853     89/<- %esp 5/r32/ebp
  854     5d/pop-to-ebp
  855     c3/return
  856 
  857 test-convert-function-call-with-literal-arg:
  858     # . prologue
  859     55/push-ebp
  860     89/<- %ebp 4/r32/esp
  861     # setup
  862     (clear-stream _test-input-stream)
  863     (clear-stream $_test-input-buffered-file->buffer)
  864     (clear-stream _test-output-stream)
  865     (clear-stream $_test-output-buffered-file->buffer)
  866     #
  867     (write _test-input-stream "fn main -> result/ebx: int {\n")
  868     (write _test-input-stream "  result <- do-add 3 4\n")
  869     (write _test-input-stream "}\n")
  870     (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
  871     (write _test-input-stream "  result <- copy a\n")
  872     (write _test-input-stream "  result <- add b\n")
  873     (write _test-input-stream "}\n")
  874     # convert
  875     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  876     (flush _test-output-buffered-file)
  877 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  883     # check output
  884     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
  885     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
  886     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
  887     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
  888     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
  889     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
  890     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
  891     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
  892     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
  893     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
  894     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
  895     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
  896     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
  897     (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
  898     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
  899     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
  900     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
  901     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
  902     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
  903     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
  904     (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
  905     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
  906     (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
  907     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
  908     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
  909     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
  910     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
  911     # . epilogue
  912     89/<- %esp 5/r32/ebp
  913     5d/pop-to-ebp
  914     c3/return
  915 
  916 test-convert-function-call-with-signature:
  917     # . prologue
  918     55/push-ebp
  919     89/<- %ebp 4/r32/esp
  920     # setup
  921     (clear-stream _test-input-stream)
  922     (clear-stream $_test-input-buffered-file->buffer)
  923     (clear-stream _test-output-stream)
  924     (clear-stream $_test-output-buffered-file->buffer)
  925     #
  926     (write _test-input-stream "fn main -> result/ebx: int {\n")
  927     (write _test-input-stream "  result <- do-add 3 4\n")
  928     (write _test-input-stream "}\n")
  929     (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
  930     # convert
  931     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  932     (flush _test-output-buffered-file)
  933 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  939     # check output
  940     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
  941     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
  942     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
  943     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
  944     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
  945     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
  946     (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
  947     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
  948     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
  949     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
  950     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
  951     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
  952     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
  953     # . epilogue
  954     89/<- %esp 5/r32/ebp
  955     5d/pop-to-ebp
  956     c3/return
  957 
  958 test-convert-function-with-local-var-in-mem:
  959     # . prologue
  960     55/push-ebp
  961     89/<- %ebp 4/r32/esp
  962     # setup
  963     (clear-stream _test-input-stream)
  964     (clear-stream $_test-input-buffered-file->buffer)
  965     (clear-stream _test-output-stream)
  966     (clear-stream $_test-output-buffered-file->buffer)
  967     #
  968     (write _test-input-stream "fn foo {\n")
  969     (write _test-input-stream "  var x: int\n")
  970     (write _test-input-stream "  increment x\n")
  971     (write _test-input-stream "}\n")
  972     # convert
  973     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
  974     (flush _test-output-buffered-file)
  975 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
  981     # check output
  982     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
  983     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
  984     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
  985     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
  986     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
  987     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
  988     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
  989     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
  990     (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")
  991     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
  992     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
  993     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
  994     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
  995     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
  996     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
  997     # . epilogue
  998     89/<- %esp 5/r32/ebp
  999     5d/pop-to-ebp
 1000     c3/return
 1001 
 1002 test-local-var-in-mem-has-no-initializer:
 1003     # . prologue
 1004     55/push-ebp
 1005     89/<- %ebp 4/r32/esp
 1006     # setup
 1007     (clear-stream _test-input-stream)
 1008     (clear-stream $_test-input-buffered-file->buffer)
 1009     (clear-stream _test-output-stream)
 1010     (clear-stream $_test-output-buffered-file->buffer)
 1011     (clear-stream _test-error-stream)
 1012     (clear-stream $_test-error-buffered-file->buffer)
 1013     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1014     68/push 0/imm32
 1015     68/push 0/imm32
 1016     89/<- %edx 4/r32/esp
 1017     (tailor-exit-descriptor %edx 0x10)
 1018     #
 1019     (write _test-input-stream "fn foo {\n")
 1020     (write _test-input-stream "  var x: int <- copy 0\n")
 1021     (write _test-input-stream "  increment x\n")
 1022     (write _test-input-stream "}\n")
 1023     # convert
 1024     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1025     # registers except esp clobbered at this point
 1026     # restore ed
 1027     89/<- %edx 4/r32/esp
 1028     (flush _test-output-buffered-file)
 1029     (flush _test-error-buffered-file)
 1030 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1036     # check output
 1037     (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
 1038     (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")
 1039     # check that stop(1) was called
 1040     (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
 1041     # don't restore from ebp
 1042     81 0/subop/add %esp 8/imm32
 1043     # . epilogue
 1044     5d/pop-to-ebp
 1045     c3/return
 1046 
 1047 test-convert-function-with-local-var-with-compound-type-in-mem:
 1048     # . prologue
 1049     55/push-ebp
 1050     89/<- %ebp 4/r32/esp
 1051     # setup
 1052     (clear-stream _test-input-stream)
 1053     (clear-stream $_test-input-buffered-file->buffer)
 1054     (clear-stream _test-output-stream)
 1055     (clear-stream $_test-output-buffered-file->buffer)
 1056     #
 1057     (write _test-input-stream "fn foo {\n")
 1058     (write _test-input-stream "  var x: (addr int)\n")
 1059     (write _test-input-stream "  copy-to x, 0\n")
 1060     (write _test-input-stream "}\n")
 1061     # convert
 1062     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1063     (flush _test-output-buffered-file)
 1064 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1070     # check output
 1071     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
 1072     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
 1073     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
 1074     (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")
 1075     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
 1076     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
 1077     (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")
 1078     (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")
 1079     (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")
 1080     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
 1081     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
 1082     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
 1083     (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")
 1084     (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")
 1085     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
 1086     # . epilogue
 1087     89/<- %esp 5/r32/ebp
 1088     5d/pop-to-ebp
 1089     c3/return
 1090 
 1091 test-convert-function-with-local-var-in-reg:
 1092     # . prologue
 1093     55/push-ebp
 1094     89/<- %ebp 4/r32/esp
 1095     # setup
 1096     (clear-stream _test-input-stream)
 1097     (clear-stream $_test-input-buffered-file->buffer)
 1098     (clear-stream _test-output-stream)
 1099     (clear-stream $_test-output-buffered-file->buffer)
 1100     #
 1101     (write _test-input-stream "fn foo {\n")
 1102     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1103     (write _test-input-stream "  x <- increment\n")
 1104     (write _test-input-stream "}\n")
 1105     # convert
 1106     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1107     (flush _test-output-buffered-file)
 1108 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1114     # check output
 1115     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
 1116     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
 1117     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
 1118     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
 1119     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
 1120     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
 1121     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
 1122     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
 1123     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
 1124     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
 1125     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
 1126     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
 1127     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
 1128     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
 1129     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
 1130     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
 1131     # . epilogue
 1132     89/<- %esp 5/r32/ebp
 1133     5d/pop-to-ebp
 1134     c3/return
 1135 
 1136 test-convert-function-with-second-local-var-in-same-reg:
 1137     # . prologue
 1138     55/push-ebp
 1139     89/<- %ebp 4/r32/esp
 1140     # setup
 1141     (clear-stream _test-input-stream)
 1142     (clear-stream $_test-input-buffered-file->buffer)
 1143     (clear-stream _test-output-stream)
 1144     (clear-stream $_test-output-buffered-file->buffer)
 1145     #
 1146     (write _test-input-stream "fn foo {\n")
 1147     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1148     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1149     (write _test-input-stream "  y <- increment\n")
 1150     (write _test-input-stream "}\n")
 1151     # convert
 1152     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1153     (flush _test-output-buffered-file)
 1154 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1160     # check output
 1161     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
 1162     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
 1163     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
 1164     (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")
 1165     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
 1166     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
 1167     (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")
 1168     (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")
 1169     (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")
 1170     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
 1171     (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")
 1172     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
 1173     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
 1174     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
 1175     (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")
 1176     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
 1177     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
 1178     # . epilogue
 1179     89/<- %esp 5/r32/ebp
 1180     5d/pop-to-ebp
 1181     c3/return
 1182 
 1183 test-read-clobbered-reg-var:
 1184     # . prologue
 1185     55/push-ebp
 1186     89/<- %ebp 4/r32/esp
 1187     # setup
 1188     (clear-stream _test-input-stream)
 1189     (clear-stream $_test-input-buffered-file->buffer)
 1190     (clear-stream _test-output-stream)
 1191     (clear-stream $_test-output-buffered-file->buffer)
 1192     (clear-stream _test-error-stream)
 1193     (clear-stream $_test-error-buffered-file->buffer)
 1194     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 1195     68/push 0/imm32
 1196     68/push 0/imm32
 1197     89/<- %edx 4/r32/esp
 1198     (tailor-exit-descriptor %edx 0x10)
 1199     #
 1200     (write _test-input-stream "fn foo {\n")
 1201     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1202     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 1203     (write _test-input-stream "  x <- increment\n")
 1204     (write _test-input-stream "}\n")
 1205     # convert
 1206     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1207     # registers except esp clobbered at this point
 1208     # restore ed
 1209     89/<- %edx 4/r32/esp
 1210     (flush _test-output-buffered-file)
 1211     (flush _test-error-buffered-file)
 1212 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1218     # check output
 1219     (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
 1220     (check-next-stream-line-equal _test-error-stream  "fn foo: register ecx reads var 'x' after writing var 'y'"  "F - test-read-clobbered-reg-var: error message")
 1221     # check that stop(1) was called
 1222     (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
 1223     # don't restore from ebp
 1224     81 0/subop/add %esp 8/imm32
 1225     # . epilogue
 1226     5d/pop-to-ebp
 1227     c3/return
 1228 
 1229 test-convert-function-call:
 1230     # . prologue
 1231     55/push-ebp
 1232     89/<- %ebp 4/r32/esp
 1233     # setup
 1234     (clear-stream _test-input-stream)
 1235     (clear-stream $_test-input-buffered-file->buffer)
 1236     (clear-stream _test-output-stream)
 1237     (clear-stream $_test-output-buffered-file->buffer)
 1238     #
 1239     (write _test-input-stream "fn main -> result/ebx: int {\n")
 1240     (write _test-input-stream "  result <- foo\n")
 1241     (write _test-input-stream "}\n")
 1242     (write _test-input-stream "fn foo -> result/ebx: int {\n")
 1243     (write _test-input-stream "  result <- copy 3\n")
 1244     (write _test-input-stream "}\n")
 1245     # convert
 1246     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1247     (flush _test-output-buffered-file)
 1248 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1254     # check output
 1255     (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
 1256     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
 1257     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
 1258     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
 1259     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
 1260     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
 1261     (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
 1262     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
 1263     (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
 1264     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
 1265     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
 1266     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
 1267     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
 1268     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
 1269     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
 1270     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
 1271     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
 1272     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
 1273     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
 1274     (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
 1275     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
 1276     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
 1277     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
 1278     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
 1279     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
 1280     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
 1281     # . epilogue
 1282     89/<- %esp 5/r32/ebp
 1283     5d/pop-to-ebp
 1284     c3/return
 1285 
 1286 test-convert-function-call-with-incorrect-inout-type:
 1287     # . prologue
 1288     55/push-ebp
 1289     89/<- %ebp 4/r32/esp
 1290     # setup
 1291     (clear-stream _test-input-stream)
 1292     (clear-stream $_test-input-buffered-file->buffer)
 1293     (clear-stream _test-output-stream)
 1294     (clear-stream $_test-output-buffered-file->buffer)
 1295     (clear-stream _test-error-stream)
 1296     (clear-stream $_test-error-buffered-file->buffer)
 1297     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1298     68/push 0/imm32
 1299     68/push 0/imm32
 1300     89/<- %edx 4/r32/esp
 1301     (tailor-exit-descriptor %edx 0x10)
 1302     #
 1303     (write _test-input-stream "fn f {\n")
 1304     (write _test-input-stream "  var x: int\n")
 1305     (write _test-input-stream "  g x\n")
 1306     (write _test-input-stream "}\n")
 1307     (write _test-input-stream "fn g a: foo {\n")
 1308     (write _test-input-stream "}\n")
 1309     # convert
 1310     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1311     # registers except esp clobbered at this point
 1312     # restore ed
 1313     89/<- %edx 4/r32/esp
 1314     (flush _test-output-buffered-file)
 1315     (flush _test-error-buffered-file)
 1316 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1322     # check output
 1323     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
 1324     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
 1325     # check that stop(1) was called
 1326     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
 1327     # don't restore from ebp
 1328     81 0/subop/add %esp 8/imm32
 1329     5d/pop-to-ebp
 1330     c3/return
 1331 
 1332 test-convert-function-call-with-too-few-inouts:
 1333     # . prologue
 1334     55/push-ebp
 1335     89/<- %ebp 4/r32/esp
 1336     # setup
 1337     (clear-stream _test-input-stream)
 1338     (clear-stream $_test-input-buffered-file->buffer)
 1339     (clear-stream _test-output-stream)
 1340     (clear-stream $_test-output-buffered-file->buffer)
 1341     (clear-stream _test-error-stream)
 1342     (clear-stream $_test-error-buffered-file->buffer)
 1343     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1344     68/push 0/imm32
 1345     68/push 0/imm32
 1346     89/<- %edx 4/r32/esp
 1347     (tailor-exit-descriptor %edx 0x10)
 1348     #
 1349     (write _test-input-stream "fn f {\n")
 1350     (write _test-input-stream "  g\n")
 1351     (write _test-input-stream "}\n")
 1352     (write _test-input-stream "fn g a: int {\n")
 1353     (write _test-input-stream "}\n")
 1354     # convert
 1355     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1356     # registers except esp clobbered at this point
 1357     # restore ed
 1358     89/<- %edx 4/r32/esp
 1359     (flush _test-output-buffered-file)
 1360     (flush _test-error-buffered-file)
 1361 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1367     # check output
 1368     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
 1369     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few inouts"  "F - test-convert-function-call-with-too-few-inouts: error message")
 1370     # check that stop(1) was called
 1371     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
 1372     # don't restore from ebp
 1373     81 0/subop/add %esp 8/imm32
 1374     5d/pop-to-ebp
 1375     c3/return
 1376 
 1377 test-convert-function-call-with-too-many-inouts:
 1378     # . prologue
 1379     55/push-ebp
 1380     89/<- %ebp 4/r32/esp
 1381     # setup
 1382     (clear-stream _test-input-stream)
 1383     (clear-stream $_test-input-buffered-file->buffer)
 1384     (clear-stream _test-output-stream)
 1385     (clear-stream $_test-output-buffered-file->buffer)
 1386     (clear-stream _test-error-stream)
 1387     (clear-stream $_test-error-buffered-file->buffer)
 1388     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1389     68/push 0/imm32
 1390     68/push 0/imm32
 1391     89/<- %edx 4/r32/esp
 1392     (tailor-exit-descriptor %edx 0x10)
 1393     #
 1394     (write _test-input-stream "fn f {\n")
 1395     (write _test-input-stream "  var x: int\n")
 1396     (write _test-input-stream "  g x\n")
 1397     (write _test-input-stream "}\n")
 1398     (write _test-input-stream "fn g {\n")
 1399     (write _test-input-stream "}\n")
 1400     # convert
 1401     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1402     # registers except esp clobbered at this point
 1403     # restore ed
 1404     89/<- %edx 4/r32/esp
 1405     (flush _test-output-buffered-file)
 1406     (flush _test-error-buffered-file)
 1407 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1413     # check output
 1414     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
 1415     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many inouts"  "F - test-convert-function-call-with-too-many-inouts: error message")
 1416     # check that stop(1) was called
 1417     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
 1418     # don't restore from ebp
 1419     81 0/subop/add %esp 8/imm32
 1420     5d/pop-to-ebp
 1421     c3/return
 1422 
 1423 test-convert-function-call-with-incorrect-output-type:
 1424     # . prologue
 1425     55/push-ebp
 1426     89/<- %ebp 4/r32/esp
 1427     # setup
 1428     (clear-stream _test-input-stream)
 1429     (clear-stream $_test-input-buffered-file->buffer)
 1430     (clear-stream _test-output-stream)
 1431     (clear-stream $_test-output-buffered-file->buffer)
 1432     (clear-stream _test-error-stream)
 1433     (clear-stream $_test-error-buffered-file->buffer)
 1434     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1435     68/push 0/imm32
 1436     68/push 0/imm32
 1437     89/<- %edx 4/r32/esp
 1438     (tailor-exit-descriptor %edx 0x10)
 1439     #
 1440     (write _test-input-stream "fn f {\n")
 1441     (write _test-input-stream "  var x/eax: int <- g\n")
 1442     (write _test-input-stream "}\n")
 1443     (write _test-input-stream "fn g -> a/eax: foo {\n")
 1444     (write _test-input-stream "}\n")
 1445     # convert
 1446     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1447     # registers except esp clobbered at this point
 1448     # restore ed
 1449     89/<- %edx 4/r32/esp
 1450     (flush _test-output-buffered-file)
 1451     (flush _test-error-buffered-file)
 1452 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1458     # check output
 1459     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
 1460     (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-type: error message")
 1461     # check that stop(1) was called
 1462     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
 1463     # don't restore from ebp
 1464     81 0/subop/add %esp 8/imm32
 1465     5d/pop-to-ebp
 1466     c3/return
 1467 
 1468 test-convert-function-call-with-too-few-outputs:
 1469     # . prologue
 1470     55/push-ebp
 1471     89/<- %ebp 4/r32/esp
 1472     # setup
 1473     (clear-stream _test-input-stream)
 1474     (clear-stream $_test-input-buffered-file->buffer)
 1475     (clear-stream _test-output-stream)
 1476     (clear-stream $_test-output-buffered-file->buffer)
 1477     (clear-stream _test-error-stream)
 1478     (clear-stream $_test-error-buffered-file->buffer)
 1479     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1480     68/push 0/imm32
 1481     68/push 0/imm32
 1482     89/<- %edx 4/r32/esp
 1483     (tailor-exit-descriptor %edx 0x10)
 1484     #
 1485     (write _test-input-stream "fn f {\n")
 1486     (write _test-input-stream "  g\n")
 1487     (write _test-input-stream "}\n")
 1488     (write _test-input-stream "fn g -> a/eax: int {\n")
 1489     (write _test-input-stream "}\n")
 1490     # convert
 1491     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1492     # registers except esp clobbered at this point
 1493     # restore ed
 1494     89/<- %edx 4/r32/esp
 1495     (flush _test-output-buffered-file)
 1496     (flush _test-error-buffered-file)
 1497 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1503     # check output
 1504     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
 1505     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few outputs"  "F - test-convert-function-call-with-too-few-outputs: error message")
 1506     # check that stop(1) was called
 1507     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
 1508     # don't restore from ebp
 1509     81 0/subop/add %esp 8/imm32
 1510     5d/pop-to-ebp
 1511     c3/return
 1512 
 1513 test-convert-function-call-with-too-many-outputs:
 1514     # . prologue
 1515     55/push-ebp
 1516     89/<- %ebp 4/r32/esp
 1517     # setup
 1518     (clear-stream _test-input-stream)
 1519     (clear-stream $_test-input-buffered-file->buffer)
 1520     (clear-stream _test-output-stream)
 1521     (clear-stream $_test-output-buffered-file->buffer)
 1522     (clear-stream _test-error-stream)
 1523     (clear-stream $_test-error-buffered-file->buffer)
 1524     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1525     68/push 0/imm32
 1526     68/push 0/imm32
 1527     89/<- %edx 4/r32/esp
 1528     (tailor-exit-descriptor %edx 0x10)
 1529     #
 1530     (write _test-input-stream "fn f {\n")
 1531     (write _test-input-stream "  var x/eax: int <- g\n")
 1532     (write _test-input-stream "}\n")
 1533     (write _test-input-stream "fn g {\n")
 1534     (write _test-input-stream "}\n")
 1535     # convert
 1536     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1537     # registers except esp clobbered at this point
 1538     # restore ed
 1539     89/<- %edx 4/r32/esp
 1540     (flush _test-output-buffered-file)
 1541     (flush _test-error-buffered-file)
 1542 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1548     # check output
 1549     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
 1550     (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many outputs"  "F - test-convert-function-call-with-too-many-outputs: error message")
 1551     # check that stop(1) was called
 1552     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
 1553     # don't restore from ebp
 1554     81 0/subop/add %esp 8/imm32
 1555     5d/pop-to-ebp
 1556     c3/return
 1557 
 1558 test-convert-function-call-with-incorrect-output-register:
 1559     # . prologue
 1560     55/push-ebp
 1561     89/<- %ebp 4/r32/esp
 1562     # setup
 1563     (clear-stream _test-input-stream)
 1564     (clear-stream $_test-input-buffered-file->buffer)
 1565     (clear-stream _test-output-stream)
 1566     (clear-stream $_test-output-buffered-file->buffer)
 1567     (clear-stream _test-error-stream)
 1568     (clear-stream $_test-error-buffered-file->buffer)
 1569     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1570     68/push 0/imm32
 1571     68/push 0/imm32
 1572     89/<- %edx 4/r32/esp
 1573     (tailor-exit-descriptor %edx 0x10)
 1574     #
 1575     (write _test-input-stream "fn f {\n")
 1576     (write _test-input-stream "  var x/ecx: int <- g\n")
 1577     (write _test-input-stream "}\n")
 1578     (write _test-input-stream "fn g -> a/eax: int {\n")
 1579     (write _test-input-stream "}\n")
 1580     # convert
 1581     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1582     # registers except esp clobbered at this point
 1583     # restore ed
 1584     89/<- %edx 4/r32/esp
 1585     (flush _test-output-buffered-file)
 1586     (flush _test-error-buffered-file)
 1587 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1593     # check output
 1594     (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
 1595     (check-next-stream-line-equal _test-error-stream  "fn f: call g: register for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-register: error message")
 1596     # check that stop(1) was called
 1597     (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
 1598     # don't restore from ebp
 1599     81 0/subop/add %esp 8/imm32
 1600     5d/pop-to-ebp
 1601     c3/return
 1602 
 1603 test-convert-function-with-local-var-dereferenced:
 1604     # . prologue
 1605     55/push-ebp
 1606     89/<- %ebp 4/r32/esp
 1607     # setup
 1608     (clear-stream _test-input-stream)
 1609     (clear-stream $_test-input-buffered-file->buffer)
 1610     (clear-stream _test-output-stream)
 1611     (clear-stream $_test-output-buffered-file->buffer)
 1612     #
 1613     (write _test-input-stream "fn foo {\n")
 1614     (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
 1615     (write _test-input-stream "  increment *x\n")
 1616     (write _test-input-stream "}\n")
 1617     # convert
 1618     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1619     (flush _test-output-buffered-file)
 1620 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1626     # check output
 1627     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
 1628     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
 1629     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
 1630     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
 1631     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
 1632     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
 1633     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
 1634     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
 1635     (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
 1636     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
 1637     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
 1638     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
 1639     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
 1640     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
 1641     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
 1642     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
 1643     # . epilogue
 1644     89/<- %esp 5/r32/ebp
 1645     5d/pop-to-ebp
 1646     c3/return
 1647 
 1648 # variables of type 'byte' are not allowed on the stack
 1649 test-convert-function-with-byte-operations:
 1650     # . prologue
 1651     55/push-ebp
 1652     89/<- %ebp 4/r32/esp
 1653     # setup
 1654     (clear-stream _test-input-stream)
 1655     (clear-stream $_test-input-buffered-file->buffer)
 1656     (clear-stream _test-output-stream)
 1657     (clear-stream $_test-output-buffered-file->buffer)
 1658     #
 1659     (write _test-input-stream "fn foo {\n")
 1660     (write _test-input-stream "  var x/eax: byte <- copy 0\n")
 1661     (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
 1662     (write _test-input-stream "  y <- copy-byte x\n")
 1663     (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
 1664     (write _test-input-stream "  y <- copy-byte *z\n")
 1665     (write _test-input-stream "  copy-byte-to *z, x\n")
 1666     (write _test-input-stream "}\n")
 1667     # convert
 1668     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1669     (flush _test-output-buffered-file)
 1670 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1676     # check output
 1677     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
 1678     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
 1679     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
 1680     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
 1681     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
 1682     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
 1683     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
 1684     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
 1685     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
 1686     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
 1687     (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
 1688     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
 1689     (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
 1690     (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
 1691     (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
 1692     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
 1693     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
 1694     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
 1695     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
 1696     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
 1697     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
 1698     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
 1699     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
 1700     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
 1701     # . epilogue
 1702     89/<- %esp 5/r32/ebp
 1703     5d/pop-to-ebp
 1704     c3/return
 1705 
 1706 # variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
 1707 test-copy-byte-var-from-fn-arg:
 1708     # . prologue
 1709     55/push-ebp
 1710     89/<- %ebp 4/r32/esp
 1711     # setup
 1712     (clear-stream _test-input-stream)
 1713     (clear-stream $_test-input-buffered-file->buffer)
 1714     (clear-stream _test-output-stream)
 1715     (clear-stream $_test-output-buffered-file->buffer)
 1716     #
 1717     (write _test-input-stream "fn foo x: byte, y: int {\n")
 1718     (write _test-input-stream "  var a/eax: byte <- copy x\n")
 1719     (write _test-input-stream "  var b/eax: int <- copy y\n")
 1720     (write _test-input-stream "}\n")
 1721     # convert
 1722     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1723     (flush _test-output-buffered-file)
 1724 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1730     # check output
 1731     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
 1732     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
 1733     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
 1734     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
 1735     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
 1736     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
 1737     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
 1738     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
 1739     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
 1740     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
 1741     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
 1742     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
 1743     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
 1744     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
 1745     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
 1746     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
 1747     # . epilogue
 1748     89/<- %esp 5/r32/ebp
 1749     5d/pop-to-ebp
 1750     c3/return
 1751 
 1752 test-convert-compare-register-with-literal:
 1753     # . prologue
 1754     55/push-ebp
 1755     89/<- %ebp 4/r32/esp
 1756     # setup
 1757     (clear-stream _test-input-stream)
 1758     (clear-stream $_test-input-buffered-file->buffer)
 1759     (clear-stream _test-output-stream)
 1760     (clear-stream $_test-output-buffered-file->buffer)
 1761     #
 1762     (write _test-input-stream "fn foo {\n")
 1763     (write _test-input-stream "  var x/ecx: int <- copy 0\n")
 1764     (write _test-input-stream "  compare x, 0\n")
 1765     (write _test-input-stream "}\n")
 1766     # convert
 1767     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1768     (flush _test-output-buffered-file)
 1769 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1775     # check output
 1776     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
 1777     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
 1778     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
 1779     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
 1780     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
 1781     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
 1782     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 1783     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
 1784     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
 1785     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 1786     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
 1787     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
 1788     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
 1789     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
 1790     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
 1791     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
 1792     # . epilogue
 1793     89/<- %esp 5/r32/ebp
 1794     5d/pop-to-ebp
 1795     c3/return
 1796 
 1797 test-unknown-variable:
 1798     # . prologue
 1799     55/push-ebp
 1800     89/<- %ebp 4/r32/esp
 1801     # setup
 1802     (clear-stream _test-input-stream)
 1803     (clear-stream $_test-input-buffered-file->buffer)
 1804     (clear-stream _test-output-stream)
 1805     (clear-stream $_test-output-buffered-file->buffer)
 1806     (clear-stream _test-error-stream)
 1807     (clear-stream $_test-error-buffered-file->buffer)
 1808     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1809     68/push 0/imm32
 1810     68/push 0/imm32
 1811     89/<- %edx 4/r32/esp
 1812     (tailor-exit-descriptor %edx 0x10)
 1813     #
 1814     (write _test-input-stream "fn foo {\n")
 1815     (write _test-input-stream "  compare x, 0\n")
 1816     (write _test-input-stream "}\n")
 1817     # convert
 1818     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1819     # registers except esp clobbered at this point
 1820     # restore ed
 1821     89/<- %edx 4/r32/esp
 1822     (flush _test-output-buffered-file)
 1823     (flush _test-error-buffered-file)
 1824 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1830     # check output
 1831     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
 1832     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
 1833     # check that stop(1) was called
 1834     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
 1835     # don't restore from ebp
 1836     81 0/subop/add %esp 8/imm32
 1837     # . epilogue
 1838     5d/pop-to-ebp
 1839     c3/return
 1840 
 1841 test-convert-function-with-local-var-in-block:
 1842     # . prologue
 1843     55/push-ebp
 1844     89/<- %ebp 4/r32/esp
 1845     # setup
 1846     (clear-stream _test-input-stream)
 1847     (clear-stream $_test-input-buffered-file->buffer)
 1848     (clear-stream _test-output-stream)
 1849     (clear-stream $_test-output-buffered-file->buffer)
 1850     #
 1851     (write _test-input-stream "fn foo {\n")
 1852     (write _test-input-stream "  {\n")
 1853     (write _test-input-stream "    var x: int\n")
 1854     (write _test-input-stream "    increment x\n")
 1855     (write _test-input-stream "  }\n")
 1856     (write _test-input-stream "}\n")
 1857     # convert
 1858     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1859     (flush _test-output-buffered-file)
 1860 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1866     # check output
 1867     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
 1868     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
 1869     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
 1870     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
 1871     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
 1872     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
 1873     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
 1874     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
 1875     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
 1876     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
 1877     (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")
 1878     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
 1879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
 1880     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
 1881     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
 1882     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
 1883     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
 1884     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
 1885     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
 1886     # . epilogue
 1887     89/<- %esp 5/r32/ebp
 1888     5d/pop-to-ebp
 1889     c3/return
 1890 
 1891 test-convert-function-with-local-var-in-named-block:
 1892     # . prologue
 1893     55/push-ebp
 1894     89/<- %ebp 4/r32/esp
 1895     # setup
 1896     (clear-stream _test-input-stream)
 1897     (clear-stream $_test-input-buffered-file->buffer)
 1898     (clear-stream _test-output-stream)
 1899     (clear-stream $_test-output-buffered-file->buffer)
 1900     #
 1901     (write _test-input-stream "fn foo {\n")
 1902     (write _test-input-stream "  $bar: {\n")
 1903     (write _test-input-stream "    var x: int\n")
 1904     (write _test-input-stream "    increment x\n")
 1905     (write _test-input-stream "  }\n")
 1906     (write _test-input-stream "}\n")
 1907     # convert
 1908     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 1909     (flush _test-output-buffered-file)
 1910 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 1916     # check output
 1917     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
 1918     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
 1919     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
 1920     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
 1921     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
 1922     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
 1923     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
 1924     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
 1925     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
 1926     (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")
 1927     (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")
 1928     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
 1929     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
 1930     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
 1931     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
 1932     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
 1933     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
 1934     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
 1935     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
 1936     # . epilogue
 1937     89/<- %esp 5/r32/ebp
 1938     5d/pop-to-ebp
 1939     c3/return
 1940 
 1941 test-unknown-variable-in-named-block:
 1942     # . prologue
 1943     55/push-ebp
 1944     89/<- %ebp 4/r32/esp
 1945     # setup
 1946     (clear-stream _test-input-stream)
 1947     (clear-stream $_test-input-buffered-file->buffer)
 1948     (clear-stream _test-output-stream)
 1949     (clear-stream $_test-output-buffered-file->buffer)
 1950     (clear-stream _test-error-stream)
 1951     (clear-stream $_test-error-buffered-file->buffer)
 1952     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 1953     68/push 0/imm32
 1954     68/push 0/imm32
 1955     89/<- %edx 4/r32/esp
 1956     (tailor-exit-descriptor %edx 0x10)
 1957     #
 1958     (write _test-input-stream "fn foo {\n")
 1959     (write _test-input-stream "  $a: {\n")
 1960     (write _test-input-stream "    compare x, 0\n")
 1961     (write _test-input-stream "  }\n")
 1962     (write _test-input-stream "}\n")
 1963     # convert
 1964     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 1965     # registers except esp clobbered at this point
 1966     # restore ed
 1967     89/<- %edx 4/r32/esp
 1968     (flush _test-output-buffered-file)
 1969     (flush _test-error-buffered-file)
 1970 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 1976     # check output
 1977     (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
 1978     (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
 1979     # check that stop(1) was called
 1980     (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
 1981     # don't restore from ebp
 1982     81 0/subop/add %esp 8/imm32
 1983     # . epilogue
 1984     5d/pop-to-ebp
 1985     c3/return
 1986 
 1987 test-always-shadow-outermost-reg-vars-in-function:
 1988     # . prologue
 1989     55/push-ebp
 1990     89/<- %ebp 4/r32/esp
 1991     # setup
 1992     (clear-stream _test-input-stream)
 1993     (clear-stream $_test-input-buffered-file->buffer)
 1994     (clear-stream _test-output-stream)
 1995     (clear-stream $_test-output-buffered-file->buffer)
 1996     #
 1997     (write _test-input-stream "fn foo {\n")
 1998     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 1999     (write _test-input-stream "}\n")
 2000     # convert
 2001     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2002     (flush _test-output-buffered-file)
 2003 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2009     # check output
 2010     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
 2011     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
 2012     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
 2013     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
 2014     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
 2015     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
 2016     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
 2017     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
 2018     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
 2019     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
 2020     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
 2021     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
 2022     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
 2023     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
 2024     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
 2025     # . epilogue
 2026     89/<- %esp 5/r32/ebp
 2027     5d/pop-to-ebp
 2028     c3/return
 2029 
 2030 _pending-test-clobber-dead-local:
 2031     # . prologue
 2032     55/push-ebp
 2033     89/<- %ebp 4/r32/esp
 2034     # setup
 2035     (clear-stream _test-input-stream)
 2036     (clear-stream $_test-input-buffered-file->buffer)
 2037     (clear-stream _test-output-stream)
 2038     (clear-stream $_test-output-buffered-file->buffer)
 2039     #
 2040     (write _test-input-stream "fn foo {\n")
 2041     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2042     (write _test-input-stream "  {\n")
 2043     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2044     (write _test-input-stream "  }\n")
 2045     (write _test-input-stream "}\n")
 2046     # convert
 2047     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2048     (flush _test-output-buffered-file)
 2049 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2055     # check output
 2056     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
 2057     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
 2058     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
 2059     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
 2060     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
 2061     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
 2062     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
 2063     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
 2064     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
 2065     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
 2066     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
 2067     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
 2068     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
 2069     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
 2070     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
 2071     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
 2072     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
 2073     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
 2074     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
 2075     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
 2076     # . epilogue
 2077     89/<- %esp 5/r32/ebp
 2078     5d/pop-to-ebp
 2079     c3/return
 2080 
 2081 test-shadow-live-local:
 2082     # . prologue
 2083     55/push-ebp
 2084     89/<- %ebp 4/r32/esp
 2085     # setup
 2086     (clear-stream _test-input-stream)
 2087     (clear-stream $_test-input-buffered-file->buffer)
 2088     (clear-stream _test-output-stream)
 2089     (clear-stream $_test-output-buffered-file->buffer)
 2090     #
 2091     (write _test-input-stream "fn foo {\n")
 2092     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2093     (write _test-input-stream "  {\n")
 2094     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2095     (write _test-input-stream "  }\n")
 2096     (write _test-input-stream "  x <- increment\n")
 2097     (write _test-input-stream "}\n")
 2098     # convert
 2099     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2100     (flush _test-output-buffered-file)
 2101 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2107     # check output
 2108     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
 2109     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
 2110     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
 2111     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
 2112     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
 2113     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
 2114     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
 2115     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
 2116     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
 2117     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
 2118     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
 2119     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
 2120     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
 2121     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
 2122     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
 2123     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
 2124     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
 2125     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
 2126     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
 2127     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
 2128     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
 2129     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
 2130     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
 2131     # . epilogue
 2132     89/<- %esp 5/r32/ebp
 2133     5d/pop-to-ebp
 2134     c3/return
 2135 
 2136 test-shadow-name:
 2137     # . prologue
 2138     55/push-ebp
 2139     89/<- %ebp 4/r32/esp
 2140     # setup
 2141     (clear-stream _test-input-stream)
 2142     (clear-stream $_test-input-buffered-file->buffer)
 2143     (clear-stream _test-output-stream)
 2144     (clear-stream $_test-output-buffered-file->buffer)
 2145     #
 2146     (write _test-input-stream "fn foo {\n")
 2147     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2148     (write _test-input-stream "  {\n")
 2149     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2150     (write _test-input-stream "  }\n")
 2151     (write _test-input-stream "  x <- increment\n")
 2152     (write _test-input-stream "}\n")
 2153     # convert
 2154     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2155     (flush _test-output-buffered-file)
 2156 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2162     # check output
 2163     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
 2164     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
 2165     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
 2166     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
 2167     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
 2168     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
 2169     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
 2170     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
 2171     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
 2172     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
 2173     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
 2174     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
 2175     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
 2176     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
 2177     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
 2178     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
 2179     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
 2180     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
 2181     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
 2182     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
 2183     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
 2184     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
 2185     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
 2186     # . epilogue
 2187     89/<- %esp 5/r32/ebp
 2188     5d/pop-to-ebp
 2189     c3/return
 2190 
 2191 test-shadow-name-2:
 2192     # . prologue
 2193     55/push-ebp
 2194     89/<- %ebp 4/r32/esp
 2195     # setup
 2196     (clear-stream _test-input-stream)
 2197     (clear-stream $_test-input-buffered-file->buffer)
 2198     (clear-stream _test-output-stream)
 2199     (clear-stream $_test-output-buffered-file->buffer)
 2200     #
 2201     (write _test-input-stream "fn foo {\n")
 2202     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2203     (write _test-input-stream "  {\n")
 2204     (write _test-input-stream "    var x/edx: int <- copy 4\n")
 2205     (write _test-input-stream "    var y/ecx: int <- copy 5\n")
 2206     (write _test-input-stream "  }\n")
 2207     (write _test-input-stream "  x <- increment\n")
 2208     (write _test-input-stream "}\n")
 2209     # convert
 2210     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2211     (flush _test-output-buffered-file)
 2212 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2218     # check output
 2219     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
 2220     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
 2221     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
 2222     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
 2223     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
 2224     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
 2225     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
 2226     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
 2227     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
 2228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
 2229     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
 2230     (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
 2231     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
 2232     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
 2233     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
 2234     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
 2235     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
 2236     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
 2237     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
 2238     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
 2239     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
 2240     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
 2241     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
 2242     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
 2243     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
 2244     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
 2245     # . epilogue
 2246     89/<- %esp 5/r32/ebp
 2247     5d/pop-to-ebp
 2248     c3/return
 2249 
 2250 test-do-not-spill-same-register-in-block:
 2251     # . prologue
 2252     55/push-ebp
 2253     89/<- %ebp 4/r32/esp
 2254     # setup
 2255     (clear-stream _test-input-stream)
 2256     (clear-stream $_test-input-buffered-file->buffer)
 2257     (clear-stream _test-output-stream)
 2258     (clear-stream $_test-output-buffered-file->buffer)
 2259     #
 2260     (write _test-input-stream "fn foo {\n")
 2261     (write _test-input-stream "  var x/ecx: int <- copy 3\n")
 2262     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2263     (write _test-input-stream "  y <- increment\n")
 2264     (write _test-input-stream "}\n")
 2265     # convert
 2266     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2267     (flush _test-output-buffered-file)
 2268 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2274     # check output
 2275     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
 2276     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
 2277     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
 2278     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
 2279     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
 2280     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
 2281     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
 2282     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
 2283     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
 2284     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
 2285     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
 2286     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
 2287     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
 2288     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
 2289     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
 2290     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
 2291     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
 2292     # . epilogue
 2293     89/<- %esp 5/r32/ebp
 2294     5d/pop-to-ebp
 2295     c3/return
 2296 
 2297 test-spill-different-register-in-block:
 2298     # . prologue
 2299     55/push-ebp
 2300     89/<- %ebp 4/r32/esp
 2301     # setup
 2302     (clear-stream _test-input-stream)
 2303     (clear-stream $_test-input-buffered-file->buffer)
 2304     (clear-stream _test-output-stream)
 2305     (clear-stream $_test-output-buffered-file->buffer)
 2306     #
 2307     (write _test-input-stream "fn foo {\n")
 2308     (write _test-input-stream "  var x/eax: int <- copy 3\n")
 2309     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2310     (write _test-input-stream "  y <- increment\n")
 2311     (write _test-input-stream "}\n")
 2312     # convert
 2313     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2314     (flush _test-output-buffered-file)
 2315 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2321     # check output
 2322     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
 2323     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
 2324     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
 2325     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
 2326     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
 2327     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
 2328     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
 2329     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
 2330     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
 2331     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
 2332     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
 2333     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
 2334     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
 2335     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
 2336     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
 2337     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
 2338     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
 2339     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
 2340     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
 2341     # . epilogue
 2342     89/<- %esp 5/r32/ebp
 2343     5d/pop-to-ebp
 2344     c3/return
 2345 
 2346 test-shadow-live-output:
 2347     # . prologue
 2348     55/push-ebp
 2349     89/<- %ebp 4/r32/esp
 2350     # setup
 2351     (clear-stream _test-input-stream)
 2352     (clear-stream $_test-input-buffered-file->buffer)
 2353     (clear-stream _test-output-stream)
 2354     (clear-stream $_test-output-buffered-file->buffer)
 2355     #
 2356     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2357     (write _test-input-stream "  x <- copy 3\n")
 2358     (write _test-input-stream "  {\n")
 2359     (write _test-input-stream "    var y/ecx: int <- copy 4\n")
 2360     (write _test-input-stream "  }\n")
 2361     (write _test-input-stream "  x <- increment\n")
 2362     (write _test-input-stream "}\n")
 2363     # convert
 2364     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2365     (flush _test-output-buffered-file)
 2366 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2372     # check output
 2373     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
 2374     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
 2375     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
 2376     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
 2377     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
 2378     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
 2379     (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
 2380     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
 2381     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
 2382     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
 2383     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
 2384     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
 2385     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
 2386     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
 2387     (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
 2388     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
 2389     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
 2390     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
 2391     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
 2392     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
 2393     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
 2394     # . epilogue
 2395     89/<- %esp 5/r32/ebp
 2396     5d/pop-to-ebp
 2397     c3/return
 2398 
 2399 test-stmt-defines-output-in-same-register-as-inout:
 2400     # . prologue
 2401     55/push-ebp
 2402     89/<- %ebp 4/r32/esp
 2403     # setup
 2404     (clear-stream _test-input-stream)
 2405     (clear-stream $_test-input-buffered-file->buffer)
 2406     (clear-stream _test-output-stream)
 2407     (clear-stream $_test-output-buffered-file->buffer)
 2408     (clear-stream _test-error-stream)
 2409     (clear-stream $_test-error-buffered-file->buffer)
 2410     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 2411     68/push 0/imm32
 2412     68/push 0/imm32
 2413     89/<- %edx 4/r32/esp
 2414     (tailor-exit-descriptor %edx 0x10)
 2415     #
 2416     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2417     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2418     (write _test-input-stream "  x <- copy y\n")  # writing to a fn output is currently the only way for a statement to define a new var
 2419     (write _test-input-stream "}\n")
 2420     # convert
 2421     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 2422     # registers except esp clobbered at this point
 2423     # restore ed
 2424     89/<- %edx 4/r32/esp
 2425     (flush _test-output-buffered-file)
 2426     (flush _test-error-buffered-file)
 2427 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2433     # no error; we looked up 'y' correctly before pushing the binding for 'x'
 2434     (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
 2435     # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
 2436     # don't restore from ebp
 2437     81 0/subop/add %esp 8/imm32
 2438     # . epilogue
 2439     5d/pop-to-ebp
 2440     c3/return
 2441 
 2442 test-local-clobbered-by-fn-output:
 2443     # . prologue
 2444     55/push-ebp
 2445     89/<- %ebp 4/r32/esp
 2446     # setup
 2447     (clear-stream _test-input-stream)
 2448     (clear-stream $_test-input-buffered-file->buffer)
 2449     (clear-stream _test-output-stream)
 2450     (clear-stream $_test-output-buffered-file->buffer)
 2451     #
 2452     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2453     (write _test-input-stream "  var y/ecx: int <- copy 4\n")
 2454     (write _test-input-stream "  x <- copy y\n")
 2455     (write _test-input-stream "}\n")
 2456     # convert
 2457     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2458     (flush _test-output-buffered-file)
 2459 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2465     # check output
 2466     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
 2467     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
 2468     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
 2469     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
 2470     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
 2471     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
 2472     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-fn-output/6")  # no push because it's an output reg
 2473     (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
 2474     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
 2475     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
 2476     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
 2477     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
 2478     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
 2479     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
 2480     # . epilogue
 2481     89/<- %esp 5/r32/ebp
 2482     5d/pop-to-ebp
 2483     c3/return
 2484 
 2485 test-read-output:
 2486     # . prologue
 2487     55/push-ebp
 2488     89/<- %ebp 4/r32/esp
 2489     # setup
 2490     (clear-stream _test-input-stream)
 2491     (clear-stream $_test-input-buffered-file->buffer)
 2492     (clear-stream _test-output-stream)
 2493     (clear-stream $_test-output-buffered-file->buffer)
 2494     #
 2495     (write _test-input-stream "fn foo -> x/ecx: int {\n")
 2496     (write _test-input-stream "  x <- copy 0x34\n")
 2497     (write _test-input-stream "  compare x, 0x35\n")
 2498     (write _test-input-stream "}\n")
 2499     # convert
 2500     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2501     (flush _test-output-buffered-file)
 2502 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2508     # check output
 2509     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
 2510     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
 2511     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
 2512     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
 2513     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
 2514     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
 2515     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
 2516     (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
 2517     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
 2518     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
 2519     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
 2520     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
 2521     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
 2522     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
 2523     # . epilogue
 2524     89/<- %esp 5/r32/ebp
 2525     5d/pop-to-ebp
 2526     c3/return
 2527 
 2528 test-fn-output-written-in-inner-block:
 2529     # . prologue
 2530     55/push-ebp
 2531     89/<- %ebp 4/r32/esp
 2532     # setup
 2533     (clear-stream _test-input-stream)
 2534     (clear-stream $_test-input-buffered-file->buffer)
 2535     (clear-stream _test-output-stream)
 2536     (clear-stream $_test-output-buffered-file->buffer)
 2537     #
 2538     (write _test-input-stream "fn foo -> out/edi: int {\n")
 2539     (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
 2540     (write _test-input-stream "  {\n")
 2541     (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
 2542     (write _test-input-stream "    out <- copy a\n")  # write to fn output
 2543     (write _test-input-stream "  }\n")
 2544     (write _test-input-stream "  compare a, 0\n")  # use outer local
 2545     (write _test-input-stream "}\n")
 2546     # convert
 2547     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2548     (flush _test-output-buffered-file)
 2549 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2555     # no error; defining 'out' didn't interfere with the reclamation of 'b'
 2556     # check output
 2557     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
 2558     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
 2559     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
 2560     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
 2561     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
 2562     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
 2563     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
 2564     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
 2565     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
 2566     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
 2567     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
 2568     (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
 2569     (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
 2570     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
 2571     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
 2572     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
 2573     (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
 2574     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
 2575     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
 2576     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
 2577     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
 2578     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
 2579     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
 2580     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
 2581     # . epilogue
 2582     89/<- %esp 5/r32/ebp
 2583     5d/pop-to-ebp
 2584     c3/return
 2585 
 2586 test-convert-function-with-branches-in-block:
 2587     # . prologue
 2588     55/push-ebp
 2589     89/<- %ebp 4/r32/esp
 2590     # setup
 2591     (clear-stream _test-input-stream)
 2592     (clear-stream $_test-input-buffered-file->buffer)
 2593     (clear-stream _test-output-stream)
 2594     (clear-stream $_test-output-buffered-file->buffer)
 2595     #
 2596     (write _test-input-stream "fn foo x: int {\n")
 2597     (write _test-input-stream "  {\n")
 2598     (write _test-input-stream "    break-if->=\n")
 2599     (write _test-input-stream "    loop-if-addr<\n")
 2600     (write _test-input-stream "    increment x\n")
 2601     (write _test-input-stream "    loop\n")
 2602     (write _test-input-stream "  }\n")
 2603     (write _test-input-stream "}\n")
 2604     # convert
 2605     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2606     (flush _test-output-buffered-file)
 2607 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2613     # check output
 2614     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
 2615     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
 2616     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
 2617     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
 2618     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
 2619     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
 2620     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
 2621     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
 2622     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
 2623     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
 2624     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
 2625     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
 2626     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
 2627     (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
 2628     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
 2629     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
 2630     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
 2631     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
 2632     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
 2633     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
 2634     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
 2635     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
 2636     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
 2637     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
 2638     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
 2639     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
 2640     # . epilogue
 2641     89/<- %esp 5/r32/ebp
 2642     5d/pop-to-ebp
 2643     c3/return
 2644 
 2645 test-convert-function-with-branches-in-named-block:
 2646     # . prologue
 2647     55/push-ebp
 2648     89/<- %ebp 4/r32/esp
 2649     # setup
 2650     (clear-stream _test-input-stream)
 2651     (clear-stream $_test-input-buffered-file->buffer)
 2652     (clear-stream _test-output-stream)
 2653     (clear-stream $_test-output-buffered-file->buffer)
 2654     #
 2655     (write _test-input-stream "fn foo x: int {\n")
 2656     (write _test-input-stream "  $bar: {\n")
 2657     (write _test-input-stream "    break-if->= $bar\n")
 2658     (write _test-input-stream "    loop-if-addr< $bar\n")
 2659     (write _test-input-stream "    increment x\n")
 2660     (write _test-input-stream "    loop\n")
 2661     (write _test-input-stream "  }\n")
 2662     (write _test-input-stream "}\n")
 2663     # convert
 2664     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2665     (flush _test-output-buffered-file)
 2666 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2672     # check output
 2673     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
 2674     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
 2675     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
 2676     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
 2677     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
 2678     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
 2679     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
 2680     (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
 2681     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
 2682     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
 2683     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
 2684     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
 2685     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
 2686     (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")
 2687     (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
 2688     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
 2689     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
 2690     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
 2691     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
 2692     (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
 2693     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
 2694     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
 2695     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
 2696     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
 2697     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
 2698     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
 2699     # . epilogue
 2700     89/<- %esp 5/r32/ebp
 2701     5d/pop-to-ebp
 2702     c3/return
 2703 
 2704 test-convert-function-with-var-in-nested-block:
 2705     # . prologue
 2706     55/push-ebp
 2707     89/<- %ebp 4/r32/esp
 2708     # setup
 2709     (clear-stream _test-input-stream)
 2710     (clear-stream $_test-input-buffered-file->buffer)
 2711     (clear-stream _test-output-stream)
 2712     (clear-stream $_test-output-buffered-file->buffer)
 2713     #
 2714     (write _test-input-stream "fn foo x: int {\n")
 2715     (write _test-input-stream "  {\n")
 2716     (write _test-input-stream "    {\n")
 2717     (write _test-input-stream "      var x: int\n")
 2718     (write _test-input-stream "      increment x\n")
 2719     (write _test-input-stream "    }\n")
 2720     (write _test-input-stream "  }\n")
 2721     (write _test-input-stream "}\n")
 2722     # convert
 2723     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2724     (flush _test-output-buffered-file)
 2725 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2731     # check output
 2732     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
 2733     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
 2734     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
 2735     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
 2736     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
 2737     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
 2738     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
 2739     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
 2740     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
 2741     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
 2742     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
 2743     (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
 2744     (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")
 2745     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
 2746     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
 2747     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
 2748     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
 2749     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
 2750     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
 2751     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
 2752     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
 2753     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
 2754     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
 2755     # . epilogue
 2756     89/<- %esp 5/r32/ebp
 2757     5d/pop-to-ebp
 2758     c3/return
 2759 
 2760 test-convert-function-with-multiple-vars-in-nested-blocks:
 2761     # . prologue
 2762     55/push-ebp
 2763     89/<- %ebp 4/r32/esp
 2764     # setup
 2765     (clear-stream _test-input-stream)
 2766     (clear-stream $_test-input-buffered-file->buffer)
 2767     (clear-stream _test-output-stream)
 2768     (clear-stream $_test-output-buffered-file->buffer)
 2769     #
 2770     (write _test-input-stream "fn foo x: int {\n")
 2771     (write _test-input-stream "  {\n")
 2772     (write _test-input-stream "    var x/eax: int <- copy 0\n")
 2773     (write _test-input-stream "    {\n")
 2774     (write _test-input-stream "      var y: int\n")
 2775     (write _test-input-stream "      x <- add y\n")
 2776     (write _test-input-stream "    }\n")
 2777     (write _test-input-stream "  }\n")
 2778     (write _test-input-stream "}\n")
 2779     # convert
 2780     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2781     (flush _test-output-buffered-file)
 2782 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2788     # check output
 2789     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
 2790     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
 2791     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
 2792     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
 2793     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
 2794     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
 2795     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
 2796     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
 2797     (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
 2798     (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")
 2799     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
 2800     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
 2801     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
 2802     (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")
 2803     (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")
 2804     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
 2805     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
 2806     (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
 2807     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
 2808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
 2809     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
 2810     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
 2811     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
 2812     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
 2813     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
 2814     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
 2815     # . epilogue
 2816     89/<- %esp 5/r32/ebp
 2817     5d/pop-to-ebp
 2818     c3/return
 2819 
 2820 test-convert-function-with-branches-and-local-vars:
 2821     # A conditional 'break' after a 'var' in a block is converted into a
 2822     # nested block that performs all necessary cleanup before jumping. This
 2823     # results in some ugly code duplication.
 2824     # . prologue
 2825     55/push-ebp
 2826     89/<- %ebp 4/r32/esp
 2827     # setup
 2828     (clear-stream _test-input-stream)
 2829     (clear-stream $_test-input-buffered-file->buffer)
 2830     (clear-stream _test-output-stream)
 2831     (clear-stream $_test-output-buffered-file->buffer)
 2832     #
 2833     (write _test-input-stream "fn foo {\n")
 2834     (write _test-input-stream "  {\n")
 2835     (write _test-input-stream "    var x: int\n")
 2836     (write _test-input-stream "    break-if->=\n")
 2837     (write _test-input-stream "    increment x\n")
 2838     (write _test-input-stream "  }\n")
 2839     (write _test-input-stream "}\n")
 2840     # convert
 2841     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2842     (flush _test-output-buffered-file)
 2843 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2849     # check output
 2850     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
 2851     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
 2852     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
 2853     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
 2854     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
 2855     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
 2856     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
 2857     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
 2858     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
 2859     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
 2860     (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
 2861     (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")
 2862     (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
 2863     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
 2864     (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
 2865     (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")
 2866     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
 2867     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
 2868     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
 2869     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
 2870     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
 2871     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
 2872     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
 2873     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
 2874     # . epilogue
 2875     89/<- %esp 5/r32/ebp
 2876     5d/pop-to-ebp
 2877     c3/return
 2878 
 2879 test-convert-function-with-conditional-loops-and-local-vars:
 2880     # A conditional 'loop' after a 'var' in a block is converted into a nested
 2881     # block that performs all necessary cleanup before jumping. This results
 2882     # in some ugly code duplication.
 2883     # . prologue
 2884     55/push-ebp
 2885     89/<- %ebp 4/r32/esp
 2886     # setup
 2887     (clear-stream _test-input-stream)
 2888     (clear-stream $_test-input-buffered-file->buffer)
 2889     (clear-stream _test-output-stream)
 2890     (clear-stream $_test-output-buffered-file->buffer)
 2891     #
 2892     (write _test-input-stream "fn foo {\n")
 2893     (write _test-input-stream "  {\n")
 2894     (write _test-input-stream "    var x: int\n")
 2895     (write _test-input-stream "    loop-if->=\n")
 2896     (write _test-input-stream "    increment x\n")
 2897     (write _test-input-stream "  }\n")
 2898     (write _test-input-stream "}\n")
 2899     # convert
 2900     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2901     (flush _test-output-buffered-file)
 2902 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2908     # check output
 2909     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
 2910     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
 2911     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
 2912     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
 2913     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
 2914     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
 2915     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
 2916     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
 2917     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
 2918     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
 2919     (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")
 2920     (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")
 2921     (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")
 2922     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
 2923     (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")
 2924     (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")
 2925     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
 2926     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
 2927     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
 2928     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
 2929     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
 2930     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
 2931     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
 2932     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
 2933     # . epilogue
 2934     89/<- %esp 5/r32/ebp
 2935     5d/pop-to-ebp
 2936     c3/return
 2937 
 2938 test-convert-function-with-unconditional-loops-and-local-vars:
 2939     # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
 2940     # regular block cleanup. Any instructions after 'loop' are dead and
 2941     # therefore skipped.
 2942     # . prologue
 2943     55/push-ebp
 2944     89/<- %ebp 4/r32/esp
 2945     # setup
 2946     (clear-stream _test-input-stream)
 2947     (clear-stream $_test-input-buffered-file->buffer)
 2948     (clear-stream _test-output-stream)
 2949     (clear-stream $_test-output-buffered-file->buffer)
 2950     #
 2951     (write _test-input-stream "fn foo {\n")
 2952     (write _test-input-stream "  {\n")
 2953     (write _test-input-stream "    var x: int\n")
 2954     (write _test-input-stream "    loop\n")
 2955     (write _test-input-stream "    increment x\n")
 2956     (write _test-input-stream "  }\n")
 2957     (write _test-input-stream "}\n")
 2958     # convert
 2959     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 2960     (flush _test-output-buffered-file)
 2961 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 2967     # check output
 2968     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
 2969     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
 2970     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
 2971     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
 2972     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
 2973     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
 2974     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
 2975     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
 2976     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
 2977     (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")
 2978     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
 2979     # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
 2980     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
 2981     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
 2982     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
 2983     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
 2984     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
 2985     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
 2986     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
 2987     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
 2988     # . epilogue
 2989     89/<- %esp 5/r32/ebp
 2990     5d/pop-to-ebp
 2991     c3/return
 2992 
 2993 test-convert-function-with-branches-and-loops-and-local-vars:
 2994     # . prologue
 2995     55/push-ebp
 2996     89/<- %ebp 4/r32/esp
 2997     # setup
 2998     (clear-stream _test-input-stream)
 2999     (clear-stream $_test-input-buffered-file->buffer)
 3000     (clear-stream _test-output-stream)
 3001     (clear-stream $_test-output-buffered-file->buffer)
 3002     #
 3003     (write _test-input-stream "fn foo {\n")
 3004     (write _test-input-stream "  {\n")
 3005     (write _test-input-stream "    var x: int\n")
 3006     (write _test-input-stream "    break-if->=\n")
 3007     (write _test-input-stream "    increment x\n")
 3008     (write _test-input-stream "    loop\n")
 3009     (write _test-input-stream "  }\n")
 3010     (write _test-input-stream "}\n")
 3011     # convert
 3012     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3013     (flush _test-output-buffered-file)
 3014 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3020     # check output
 3021     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
 3022     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
 3023     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
 3024     (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")
 3025     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
 3026     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
 3027     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
 3028     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
 3029     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
 3030     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
 3031     (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")
 3032     (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")
 3033     (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")
 3034     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
 3035     (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")
 3036     (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")
 3037     (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
 3038     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
 3039     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
 3040     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
 3041     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
 3042     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
 3043     (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")
 3044     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
 3045     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
 3046     # . epilogue
 3047     89/<- %esp 5/r32/ebp
 3048     5d/pop-to-ebp
 3049     c3/return
 3050 
 3051 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
 3052     # . prologue
 3053     55/push-ebp
 3054     89/<- %ebp 4/r32/esp
 3055     # setup
 3056     (clear-stream _test-input-stream)
 3057     (clear-stream $_test-input-buffered-file->buffer)
 3058     (clear-stream _test-output-stream)
 3059     (clear-stream $_test-output-buffered-file->buffer)
 3060     #
 3061     (write _test-input-stream "fn foo {\n")
 3062     (write _test-input-stream "  a: {\n")
 3063     (write _test-input-stream "    var x: int\n")
 3064     (write _test-input-stream "    {\n")
 3065     (write _test-input-stream "      var y: int\n")
 3066     (write _test-input-stream "      break-if->= a\n")
 3067     (write _test-input-stream "      increment x\n")
 3068     (write _test-input-stream "      loop\n")
 3069     (write _test-input-stream "    }\n")
 3070     (write _test-input-stream "  }\n")
 3071     (write _test-input-stream "}\n")
 3072     # convert
 3073     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3074     (flush _test-output-buffered-file)
 3075 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3081     # check output
 3082     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
 3083     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
 3084     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
 3085     (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")
 3086     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
 3087     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
 3088     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
 3089     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
 3090     (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")
 3091     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
 3092     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
 3093     (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")
 3094     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
 3095     (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")
 3096     (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")
 3097     (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")
 3098     (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")
 3099     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
 3100     (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")
 3101     (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")
 3102     (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")
 3103     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
 3104     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
 3105     (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")
 3106     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
 3107     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
 3108     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
 3109     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
 3110     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
 3111     (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")
 3112     (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")
 3113     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
 3114     # . epilogue
 3115     89/<- %esp 5/r32/ebp
 3116     5d/pop-to-ebp
 3117     c3/return
 3118 
 3119 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
 3120     # . prologue
 3121     55/push-ebp
 3122     89/<- %ebp 4/r32/esp
 3123     # setup
 3124     (clear-stream _test-input-stream)
 3125     (clear-stream $_test-input-buffered-file->buffer)
 3126     (clear-stream _test-output-stream)
 3127     (clear-stream $_test-output-buffered-file->buffer)
 3128     # non-local conditional branch from a block without a local variable,
 3129     # unwinding a local on the stack
 3130     (write _test-input-stream "fn foo {\n")
 3131     (write _test-input-stream "  a: {\n")
 3132     (write _test-input-stream "    var x: int\n")
 3133     (write _test-input-stream "    {\n")
 3134     (write _test-input-stream "      break-if->= a\n")
 3135     (write _test-input-stream "    }\n")
 3136     (write _test-input-stream "  }\n")
 3137     (write _test-input-stream "}\n")
 3138     # convert
 3139     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3140     (flush _test-output-buffered-file)
 3141 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3147     # check output
 3148     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
 3149     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
 3150     (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")
 3151     (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")
 3152     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
 3153     (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")
 3154     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
 3155     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
 3156     (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")
 3157     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
 3158     (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")
 3159     (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
 3160     (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")
 3161     (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")
 3162     (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")
 3163     (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
 3164     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
 3165     (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")
 3166     (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/18")
 3167     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
 3168     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
 3169     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
 3170     (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")
 3171     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
 3172     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/24")
 3173     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/25")
 3174     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
 3175     # . epilogue
 3176     89/<- %esp 5/r32/ebp
 3177     5d/pop-to-ebp
 3178     c3/return
 3179 
 3180 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
 3181     # . prologue
 3182     55/push-ebp
 3183     89/<- %ebp 4/r32/esp
 3184     # setup
 3185     (clear-stream _test-input-stream)
 3186     (clear-stream $_test-input-buffered-file->buffer)
 3187     (clear-stream _test-output-stream)
 3188     (clear-stream $_test-output-buffered-file->buffer)
 3189     # non-local unconditional branch from a block without a local variable,
 3190     # unwinding a local on the stack
 3191     (write _test-input-stream "fn foo {\n")
 3192     (write _test-input-stream "  a: {\n")
 3193     (write _test-input-stream "    var x: int\n")
 3194     (write _test-input-stream "    {\n")
 3195     (write _test-input-stream "      break a\n")
 3196     (write _test-input-stream "    }\n")
 3197     (write _test-input-stream "  }\n")
 3198     (write _test-input-stream "}\n")
 3199     # convert
 3200     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3201     (flush _test-output-buffered-file)
 3202 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3208     # check output
 3209     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
 3210     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
 3211     (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")
 3212     (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")
 3213     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
 3214     (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")
 3215     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
 3216     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
 3217     (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")
 3218     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
 3219     (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")
 3220     (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")
 3221     (check-next-stream-line-equal _test-output-stream "        e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/12")
 3222     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
 3223     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/15")
 3224     (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")
 3225     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
 3226     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
 3227     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
 3228     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/20")
 3229     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
 3230     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/22")
 3231     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/23")
 3232     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
 3233     # . epilogue
 3234     89/<- %esp 5/r32/ebp
 3235     5d/pop-to-ebp
 3236     c3/return
 3237 
 3238 test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
 3239     # . prologue
 3240     55/push-ebp
 3241     89/<- %ebp 4/r32/esp
 3242     # setup
 3243     (clear-stream _test-input-stream)
 3244     (clear-stream $_test-input-buffered-file->buffer)
 3245     (clear-stream _test-output-stream)
 3246     (clear-stream $_test-output-buffered-file->buffer)
 3247     #
 3248     (write _test-input-stream "fn foo {\n")
 3249     (write _test-input-stream "  a: {\n")
 3250     (write _test-input-stream "    var x/esi: int <- copy 0\n")
 3251     (write _test-input-stream "    {\n")
 3252     (write _test-input-stream "      break a\n")
 3253     (write _test-input-stream "    }\n")
 3254     (write _test-input-stream "  }\n")
 3255     (write _test-input-stream "}\n")
 3256     # convert
 3257     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3258     (flush _test-output-buffered-file)
 3259 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3265     # check output
 3266     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
 3267     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
 3268     (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")
 3269     (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")
 3270     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
 3271     (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")
 3272     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
 3273     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
 3274     (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")
 3275     (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")
 3276     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
 3277     (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")
 3278     (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")
 3279     (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")
 3280     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
 3281     (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")
 3282     (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")
 3283     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
 3284     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
 3285     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
 3286     (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")
 3287     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
 3288     (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")
 3289     (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")
 3290     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
 3291     # . epilogue
 3292     89/<- %esp 5/r32/ebp
 3293     5d/pop-to-ebp
 3294     c3/return
 3295 
 3296 test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
 3297     # . prologue
 3298     55/push-ebp
 3299     89/<- %ebp 4/r32/esp
 3300     # setup
 3301     (clear-stream _test-input-stream)
 3302     (clear-stream $_test-input-buffered-file->buffer)
 3303     (clear-stream _test-output-stream)
 3304     (clear-stream $_test-output-buffered-file->buffer)
 3305     #
 3306     (write _test-input-stream "fn foo {\n")
 3307     (write _test-input-stream "  a: {\n")
 3308     (write _test-input-stream "    var x: int\n")
 3309     (write _test-input-stream "    {\n")
 3310     (write _test-input-stream "      var y: int\n")
 3311     (write _test-input-stream "      break a\n")
 3312     (write _test-input-stream "      increment x\n")
 3313     (write _test-input-stream "    }\n")
 3314     (write _test-input-stream "  }\n")
 3315     (write _test-input-stream "}\n")
 3316     # convert
 3317     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3318     (flush _test-output-buffered-file)
 3319 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3325     # check output
 3326     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
 3327     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
 3328     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
 3329     (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")
 3330     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
 3331     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
 3332     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
 3333     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
 3334     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
 3335     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
 3336     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
 3337     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
 3338     (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")
 3339     (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")
 3340     (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")
 3341     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
 3342     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
 3343     (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")
 3344     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
 3345     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
 3346     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
 3347     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
 3348     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
 3349     (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")
 3350     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
 3351     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
 3352     # . epilogue
 3353     89/<- %esp 5/r32/ebp
 3354     5d/pop-to-ebp
 3355     c3/return
 3356 
 3357 test-convert-function-with-unconditional-break-and-local-vars:
 3358     # . prologue
 3359     55/push-ebp
 3360     89/<- %ebp 4/r32/esp
 3361     # setup
 3362     (clear-stream _test-input-stream)
 3363     (clear-stream $_test-input-buffered-file->buffer)
 3364     (clear-stream _test-output-stream)
 3365     (clear-stream $_test-output-buffered-file->buffer)
 3366     #
 3367     (write _test-input-stream "fn foo {\n")
 3368     (write _test-input-stream "  {\n")
 3369     (write _test-input-stream "    var x: int\n")
 3370     (write _test-input-stream "    {\n")
 3371     (write _test-input-stream "      var y: int\n")
 3372     (write _test-input-stream "      break\n")
 3373     (write _test-input-stream "      increment x\n")
 3374     (write _test-input-stream "    }\n")
 3375     (write _test-input-stream "  }\n")
 3376     (write _test-input-stream "}\n")
 3377     # convert
 3378     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3379     (flush _test-output-buffered-file)
 3380 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3386     # check output
 3387     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
 3388     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
 3389     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
 3390     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
 3391     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
 3392     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
 3393     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
 3394     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
 3395     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
 3396     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
 3397     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
 3398     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
 3399     (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")
 3400     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
 3401     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
 3402     (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")
 3403     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
 3404     (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
 3405     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
 3406     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
 3407     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
 3408     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
 3409     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
 3410     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
 3411     # . epilogue
 3412     89/<- %esp 5/r32/ebp
 3413     5d/pop-to-ebp
 3414     c3/return
 3415 
 3416 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
 3417     # . prologue
 3418     55/push-ebp
 3419     89/<- %ebp 4/r32/esp
 3420     # setup
 3421     (clear-stream _test-input-stream)
 3422     (clear-stream $_test-input-buffered-file->buffer)
 3423     (clear-stream _test-output-stream)
 3424     (clear-stream $_test-output-buffered-file->buffer)
 3425     #
 3426     (write _test-input-stream "fn foo {\n")
 3427     (write _test-input-stream "  a: {\n")
 3428     (write _test-input-stream "    var x: int\n")
 3429     (write _test-input-stream "    {\n")
 3430     (write _test-input-stream "      var y: int\n")
 3431     (write _test-input-stream "      loop a\n")
 3432     (write _test-input-stream "      increment x\n")
 3433     (write _test-input-stream "    }\n")
 3434     (write _test-input-stream "  }\n")
 3435     (write _test-input-stream "}\n")
 3436     # convert
 3437     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3438     (flush _test-output-buffered-file)
 3439 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3445     # check output
 3446     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
 3447     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
 3448     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
 3449     (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")
 3450     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
 3451     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
 3452     (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
 3453     (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
 3454     (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
 3455     (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
 3456     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
 3457     (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
 3458     (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")
 3459     (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")
 3460     (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")
 3461     (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
 3462     (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
 3463     (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")
 3464     (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
 3465     (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
 3466     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
 3467     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
 3468     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
 3469     (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")
 3470     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
 3471     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
 3472     # . epilogue
 3473     89/<- %esp 5/r32/ebp
 3474     5d/pop-to-ebp
 3475     c3/return
 3476 
 3477 test-convert-function-with-local-array-var-in-mem:
 3478     # . prologue
 3479     55/push-ebp
 3480     89/<- %ebp 4/r32/esp
 3481     # setup
 3482     (clear-stream _test-input-stream)
 3483     (clear-stream $_test-input-buffered-file->buffer)
 3484     (clear-stream _test-output-stream)
 3485     (clear-stream $_test-output-buffered-file->buffer)
 3486     #
 3487     (write _test-input-stream "fn foo {\n")
 3488     (write _test-input-stream "  var x: (array int 3)\n")
 3489     (write _test-input-stream "}\n")
 3490     # convert
 3491     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3492     (flush _test-output-buffered-file)
 3493 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3499     # check output
 3500     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
 3501     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
 3502     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
 3503     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
 3504     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
 3505     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
 3506     # define x
 3507     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
 3508     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
 3509     # reclaim x
 3510     (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")
 3511     #
 3512     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
 3513     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
 3514     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
 3515     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
 3516     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
 3517     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
 3518     # . epilogue
 3519     89/<- %esp 5/r32/ebp
 3520     5d/pop-to-ebp
 3521     c3/return
 3522 
 3523 # special-case for size(byte) when allocating array
 3524 test-convert-function-with-local-array-of-bytes-in-mem:
 3525     # . prologue
 3526     55/push-ebp
 3527     89/<- %ebp 4/r32/esp
 3528     # setup
 3529     (clear-stream _test-input-stream)
 3530     (clear-stream $_test-input-buffered-file->buffer)
 3531     (clear-stream _test-output-stream)
 3532     (clear-stream $_test-output-buffered-file->buffer)
 3533     #
 3534     (write _test-input-stream "fn foo {\n")
 3535     (write _test-input-stream "  var x: (array byte 3)\n")
 3536     (write _test-input-stream "}\n")
 3537     # convert
 3538     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3539     (flush _test-output-buffered-file)
 3540 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3546     # check output
 3547     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
 3548     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
 3549     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
 3550     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/3")
 3551     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
 3552     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
 3553     # define x
 3554     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"  "F - test-convert-function-with-local-array-of-bytes-in-mem/7")
 3555     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
 3556     # reclaim x
 3557     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/9")
 3558     #
 3559     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
 3560     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
 3561     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
 3562     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/13")
 3563     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
 3564     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
 3565     # . epilogue
 3566     89/<- %esp 5/r32/ebp
 3567     5d/pop-to-ebp
 3568     c3/return
 3569 
 3570 test-convert-address:
 3571     # . prologue
 3572     55/push-ebp
 3573     89/<- %ebp 4/r32/esp
 3574     # setup
 3575     (clear-stream _test-input-stream)
 3576     (clear-stream $_test-input-buffered-file->buffer)
 3577     (clear-stream _test-output-stream)
 3578     (clear-stream $_test-output-buffered-file->buffer)
 3579     #
 3580     (write _test-input-stream "fn foo {\n")
 3581     (write _test-input-stream "  var a: int\n")
 3582     (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
 3583     (write _test-input-stream "}\n")
 3584     # convert
 3585     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3586     (flush _test-output-buffered-file)
 3587 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3593     # check output
 3594     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
 3595     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
 3596     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
 3597     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
 3598     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
 3599     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
 3600     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
 3601     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
 3602     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
 3603     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
 3604     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
 3605     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
 3606     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
 3607     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
 3608     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
 3609     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
 3610     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
 3611     # . epilogue
 3612     89/<- %esp 5/r32/ebp
 3613     5d/pop-to-ebp
 3614     c3/return
 3615 
 3616 test-convert-length-of-array:
 3617     # . prologue
 3618     55/push-ebp
 3619     89/<- %ebp 4/r32/esp
 3620     # setup
 3621     (clear-stream _test-input-stream)
 3622     (clear-stream $_test-input-buffered-file->buffer)
 3623     (clear-stream _test-output-stream)
 3624     (clear-stream $_test-output-buffered-file->buffer)
 3625     #
 3626     (write _test-input-stream "fn foo a: (addr array int) {\n")
 3627     (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
 3628     (write _test-input-stream "  var c/eax: int <- length b\n")
 3629     (write _test-input-stream "}\n")
 3630     # convert
 3631     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3632     (flush _test-output-buffered-file)
 3633 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3639     # check output
 3640     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
 3641     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
 3642     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
 3643     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
 3644     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
 3645     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
 3646     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
 3647     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
 3648     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
 3649     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
 3650     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
 3651     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
 3652     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
 3653     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
 3654     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
 3655     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
 3656     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
 3657     # . epilogue
 3658     89/<- %esp 5/r32/ebp
 3659     5d/pop-to-ebp
 3660     c3/return
 3661 
 3662 # special-case for size(byte) when computing array length
 3663 test-convert-length-of-array-of-bytes:
 3664     # . prologue
 3665     55/push-ebp
 3666     89/<- %ebp 4/r32/esp
 3667     # setup
 3668     (clear-stream _test-input-stream)
 3669     (clear-stream $_test-input-buffered-file->buffer)
 3670     (clear-stream _test-output-stream)
 3671     (clear-stream $_test-output-buffered-file->buffer)
 3672     #
 3673     (write _test-input-stream "fn foo a: (addr array byte) {\n")
 3674     (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
 3675     (write _test-input-stream "  var c/eax: int <- length b\n")
 3676     (write _test-input-stream "}\n")
 3677     # convert
 3678     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3679     (flush _test-output-buffered-file)
 3680 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3686     # check output
 3687     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
 3688     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
 3689     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
 3690     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
 3691     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
 3692     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
 3693     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
 3694     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
 3695     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
 3696     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
 3697     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
 3698     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
 3699     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
 3700     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
 3701     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
 3702     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
 3703     # . epilogue
 3704     89/<- %esp 5/r32/ebp
 3705     5d/pop-to-ebp
 3706     c3/return
 3707 
 3708 test-convert-length-of-array-on-stack:
 3709     # . prologue
 3710     55/push-ebp
 3711     89/<- %ebp 4/r32/esp
 3712     # setup
 3713     (clear-stream _test-input-stream)
 3714     (clear-stream $_test-input-buffered-file->buffer)
 3715     (clear-stream _test-output-stream)
 3716     (clear-stream $_test-output-buffered-file->buffer)
 3717     #
 3718     (write _test-input-stream "fn foo {\n")
 3719     (write _test-input-stream "  var a: (array int 3)\n")
 3720     (write _test-input-stream "  var b/eax: int <- length a\n")
 3721     (write _test-input-stream "}\n")
 3722     # convert
 3723     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3724     (flush _test-output-buffered-file)
 3725 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3731     # check output
 3732     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
 3733     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
 3734     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
 3735     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
 3736     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
 3737     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
 3738     # define x
 3739     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
 3740     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
 3741     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
 3742     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
 3743     (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
 3744     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
 3745     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
 3746     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
 3747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
 3748     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
 3749     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
 3750     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
 3751     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
 3752     # . epilogue
 3753     89/<- %esp 5/r32/ebp
 3754     5d/pop-to-ebp
 3755     c3/return
 3756 
 3757 test-reg-var-def-with-read-of-same-register:
 3758     # . prologue
 3759     55/push-ebp
 3760     89/<- %ebp 4/r32/esp
 3761     # setup
 3762     (clear-stream _test-input-stream)
 3763     (clear-stream $_test-input-buffered-file->buffer)
 3764     (clear-stream _test-output-stream)
 3765     (clear-stream $_test-output-buffered-file->buffer)
 3766     (clear-stream _test-error-stream)
 3767     (clear-stream $_test-error-buffered-file->buffer)
 3768     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
 3769     68/push 0/imm32
 3770     68/push 0/imm32
 3771     89/<- %edx 4/r32/esp
 3772     (tailor-exit-descriptor %edx 0x10)
 3773     #
 3774     (write _test-input-stream "fn foo {\n")
 3775     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3776     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3777     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3778     (write _test-input-stream "}\n")
 3779     # convert
 3780     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 3781     # registers except esp could be clobbered at this point (though they shouldn't be)
 3782     # restore ed
 3783     89/<- %edx 4/r32/esp
 3784     (flush _test-output-buffered-file)
 3785     (flush _test-error-buffered-file)
 3786 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3792     (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
 3793     # check output
 3794     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
 3795     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
 3796     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
 3797     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
 3798     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
 3799     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
 3800     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
 3801     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-reg-var-def-with-read-of-same-register/7")
 3802     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
 3803     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-reg-var-def-with-read-of-same-register/9")
 3804     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-reg-var-def-with-read-of-same-register/11")
 3805     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
 3806     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
 3807     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
 3808     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
 3809     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
 3810     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
 3811     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
 3812     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
 3813     # don't restore from ebp
 3814     81 0/subop/add %esp 8/imm32
 3815     # . epilogue
 3816     5d/pop-to-ebp
 3817     c3/return
 3818 
 3819 test-convert-index-into-array:
 3820     # . prologue
 3821     55/push-ebp
 3822     89/<- %ebp 4/r32/esp
 3823     # setup
 3824     (clear-stream _test-input-stream)
 3825     (clear-stream $_test-input-buffered-file->buffer)
 3826     (clear-stream _test-output-stream)
 3827     (clear-stream $_test-output-buffered-file->buffer)
 3828     #
 3829     (write _test-input-stream "fn foo {\n")
 3830     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3831     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3832     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 3833     (write _test-input-stream "}\n")
 3834     # convert
 3835     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3836     (flush _test-output-buffered-file)
 3837 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3843     # check output
 3844     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
 3845     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
 3846     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
 3847     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
 3848     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
 3849     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
 3850     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
 3851     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
 3852     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
 3853     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
 3854     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
 3855     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
 3856     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
 3857     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
 3858     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
 3859     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
 3860     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
 3861     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
 3862     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
 3863     # . epilogue
 3864     89/<- %esp 5/r32/ebp
 3865     5d/pop-to-ebp
 3866     c3/return
 3867 
 3868 test-convert-index-into-array-of-bytes:
 3869     # . prologue
 3870     55/push-ebp
 3871     89/<- %ebp 4/r32/esp
 3872     # setup
 3873     (clear-stream _test-input-stream)
 3874     (clear-stream $_test-input-buffered-file->buffer)
 3875     (clear-stream _test-output-stream)
 3876     (clear-stream $_test-output-buffered-file->buffer)
 3877     #
 3878     (write _test-input-stream "fn foo {\n")
 3879     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3880     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 3881     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
 3882     (write _test-input-stream "}\n")
 3883     # convert
 3884     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3885     (flush _test-output-buffered-file)
 3886 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3892     # check output
 3893     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
 3894     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
 3895     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
 3896     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
 3897     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
 3898     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
 3899     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
 3900     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
 3901     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
 3902     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
 3903     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes/11")
 3904     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
 3905     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
 3906     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
 3907     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
 3908     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
 3909     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
 3910     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
 3911     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
 3912     # . epilogue
 3913     89/<- %esp 5/r32/ebp
 3914     5d/pop-to-ebp
 3915     c3/return
 3916 
 3917 test-convert-index-into-array-with-literal:
 3918     # . prologue
 3919     55/push-ebp
 3920     89/<- %ebp 4/r32/esp
 3921     # setup
 3922     (clear-stream _test-input-stream)
 3923     (clear-stream $_test-input-buffered-file->buffer)
 3924     (clear-stream _test-output-stream)
 3925     (clear-stream $_test-output-buffered-file->buffer)
 3926     #
 3927     (write _test-input-stream "fn foo {\n")
 3928     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 3929     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 3930     (write _test-input-stream "}\n")
 3931     # convert
 3932     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3933     (flush _test-output-buffered-file)
 3934 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3940     # check output
 3941     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
 3942     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
 3943     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
 3944     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
 3945     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
 3946     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
 3947     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
 3948     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
 3949                                                                                  # 2 * 4 bytes/elem + 4 bytes for size = offset 12
 3950     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
 3951     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
 3952     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
 3953     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
 3954     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
 3955     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
 3956     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
 3957     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
 3958     # . epilogue
 3959     89/<- %esp 5/r32/ebp
 3960     5d/pop-to-ebp
 3961     c3/return
 3962 
 3963 test-convert-index-into-array-of-bytes-with-literal:
 3964     # . prologue
 3965     55/push-ebp
 3966     89/<- %ebp 4/r32/esp
 3967     # setup
 3968     (clear-stream _test-input-stream)
 3969     (clear-stream $_test-input-buffered-file->buffer)
 3970     (clear-stream _test-output-stream)
 3971     (clear-stream $_test-output-buffered-file->buffer)
 3972     #
 3973     (write _test-input-stream "fn foo {\n")
 3974     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 3975     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 3976     (write _test-input-stream "}\n")
 3977     # convert
 3978     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 3979     (flush _test-output-buffered-file)
 3980 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 3986     # check output
 3987     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
 3988     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
 3989     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
 3990     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
 3991     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
 3992     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
 3993     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
 3994     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-with-literal/7")
 3995                                                                                  # 2 * 1 byte/elem + 4 bytes for size = offset 6
 3996     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000006) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-with-literal/8")
 3997     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
 3998     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
 3999     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
 4000     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
 4001     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
 4002     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
 4003     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
 4004     # . epilogue
 4005     89/<- %esp 5/r32/ebp
 4006     5d/pop-to-ebp
 4007     c3/return
 4008 
 4009 test-convert-index-into-array-on-stack:
 4010     # . prologue
 4011     55/push-ebp
 4012     89/<- %ebp 4/r32/esp
 4013     # setup
 4014     (clear-stream _test-input-stream)
 4015     (clear-stream $_test-input-buffered-file->buffer)
 4016     (clear-stream _test-output-stream)
 4017     (clear-stream $_test-output-buffered-file->buffer)
 4018     #
 4019     (write _test-input-stream "fn foo {\n")
 4020     (write _test-input-stream "  var arr: (array int 3)\n")
 4021     (write _test-input-stream "  var idx/eax: int <- copy 2\n")
 4022     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 4023     (write _test-input-stream "}\n")
 4024     # convert
 4025     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4026     (flush _test-output-buffered-file)
 4027 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4033     # check output
 4034     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
 4035     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
 4036     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
 4037     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
 4038     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
 4039     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
 4040     # var arr
 4041     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
 4042     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
 4043     # var idx
 4044     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
 4045     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
 4046     # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
 4047     (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")
 4048     # reclaim idx
 4049     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
 4050     # reclaim arr
 4051     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
 4052     #
 4053     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
 4054     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
 4055     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
 4056     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
 4057     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
 4058     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
 4059     # . epilogue
 4060     89/<- %esp 5/r32/ebp
 4061     5d/pop-to-ebp
 4062     c3/return
 4063 
 4064 test-convert-index-into-array-on-stack-with-literal:
 4065     # . prologue
 4066     55/push-ebp
 4067     89/<- %ebp 4/r32/esp
 4068     # setup
 4069     (clear-stream _test-input-stream)
 4070     (clear-stream $_test-input-buffered-file->buffer)
 4071     (clear-stream _test-output-stream)
 4072     (clear-stream $_test-output-buffered-file->buffer)
 4073     #
 4074     (write _test-input-stream "fn foo {\n")
 4075     (write _test-input-stream "  var arr: (array int 3)\n")
 4076     (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
 4077     (write _test-input-stream "}\n")
 4078     # convert
 4079     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4080     (flush _test-output-buffered-file)
 4081 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4087     # check output
 4088     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
 4089     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
 4090     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
 4091     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
 4092     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
 4093     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
 4094     # var arr
 4095     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
 4096     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
 4097     # var x
 4098     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
 4099     # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
 4100     (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")
 4101     # reclaim x
 4102     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
 4103     # reclaim arr
 4104     (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")
 4105     #
 4106     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
 4107     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
 4108     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
 4109     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
 4110     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
 4111     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
 4112     # . epilogue
 4113     89/<- %esp 5/r32/ebp
 4114     5d/pop-to-ebp
 4115     c3/return
 4116 
 4117 test-convert-index-into-array-of-bytes-on-stack-with-literal:
 4118     # . prologue
 4119     55/push-ebp
 4120     89/<- %ebp 4/r32/esp
 4121     # setup
 4122     (clear-stream _test-input-stream)
 4123     (clear-stream $_test-input-buffered-file->buffer)
 4124     (clear-stream _test-output-stream)
 4125     (clear-stream $_test-output-buffered-file->buffer)
 4126     #
 4127     (write _test-input-stream "fn foo {\n")
 4128     (write _test-input-stream "  var arr: (array byte 3)\n")
 4129     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
 4130     (write _test-input-stream "}\n")
 4131     # convert
 4132     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4133     (flush _test-output-buffered-file)
 4134 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4140     # check output
 4141     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
 4142     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
 4143     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
 4144     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/3")
 4145     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
 4146     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
 4147     # var arr
 4148     (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"          "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/6")
 4149     (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"                "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/7")
 4150     # var x
 4151     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/8")
 4152     # x is at (ebp-7) + 4 + 2 = ebp-1
 4153     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
 4154     # reclaim x
 4155     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10")
 4156     # reclaim arr
 4157     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11")
 4158     #
 4159     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
 4160     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
 4161     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
 4162     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
 4163     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
 4164     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
 4165     # . epilogue
 4166     89/<- %esp 5/r32/ebp
 4167     5d/pop-to-ebp
 4168     c3/return
 4169 
 4170 test-convert-index-into-array-using-offset:
 4171     # . prologue
 4172     55/push-ebp
 4173     89/<- %ebp 4/r32/esp
 4174     # setup
 4175     (clear-stream _test-input-stream)
 4176     (clear-stream $_test-input-buffered-file->buffer)
 4177     (clear-stream _test-output-stream)
 4178     (clear-stream $_test-output-buffered-file->buffer)
 4179     #
 4180     (write _test-input-stream "fn foo {\n")
 4181     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4182     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4183     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4184     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4185     (write _test-input-stream "}\n")
 4186     # convert
 4187     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4188     (flush _test-output-buffered-file)
 4189 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4195     # check output
 4196     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
 4197     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
 4198     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
 4199     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
 4200     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
 4201     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
 4202     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
 4203     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
 4204     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
 4205     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
 4206     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
 4207     (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")
 4208     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
 4209     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
 4210     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
 4211     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
 4212     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
 4213     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
 4214     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
 4215     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
 4216     # . epilogue
 4217     89/<- %esp 5/r32/ebp
 4218     5d/pop-to-ebp
 4219     c3/return
 4220 
 4221 test-convert-index-into-array-of-bytes-using-offset:
 4222     # . prologue
 4223     55/push-ebp
 4224     89/<- %ebp 4/r32/esp
 4225     # setup
 4226     (clear-stream _test-input-stream)
 4227     (clear-stream $_test-input-buffered-file->buffer)
 4228     (clear-stream _test-output-stream)
 4229     (clear-stream $_test-output-buffered-file->buffer)
 4230     #
 4231     (write _test-input-stream "fn foo {\n")
 4232     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4233     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 4234     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4235     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4236     (write _test-input-stream "}\n")
 4237     # convert
 4238     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4239     (flush _test-output-buffered-file)
 4240 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4246     # check output
 4247     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
 4248     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
 4249     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
 4250     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
 4251     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
 4252     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
 4253     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
 4254     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/7")
 4255     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
 4256     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/9")
 4257     (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/10")
 4258     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/11")
 4259     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
 4260     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
 4261     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
 4262     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
 4263     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
 4264     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
 4265     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
 4266     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
 4267     # . epilogue
 4268     89/<- %esp 5/r32/ebp
 4269     5d/pop-to-ebp
 4270     c3/return
 4271 
 4272 test-convert-index-into-array-using-offset-on-stack:
 4273     # . prologue
 4274     55/push-ebp
 4275     89/<- %ebp 4/r32/esp
 4276     # setup
 4277     (clear-stream _test-input-stream)
 4278     (clear-stream $_test-input-buffered-file->buffer)
 4279     (clear-stream _test-output-stream)
 4280     (clear-stream $_test-output-buffered-file->buffer)
 4281     #
 4282     (write _test-input-stream "fn foo {\n")
 4283     (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
 4284     (write _test-input-stream "  var idx: int\n")
 4285     (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
 4286     (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
 4287     (write _test-input-stream "}\n")
 4288     # convert
 4289     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4290     (flush _test-output-buffered-file)
 4291 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4297     # check output
 4298     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
 4299     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
 4300     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
 4301     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
 4302     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
 4303     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
 4304     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
 4305     (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")
 4306     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
 4307     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
 4308     (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")
 4309     (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")
 4310     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
 4311     (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")
 4312     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
 4313     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
 4314     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
 4315     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
 4316     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
 4317     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
 4318     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
 4319     # . epilogue
 4320     89/<- %esp 5/r32/ebp
 4321     5d/pop-to-ebp
 4322     c3/return
 4323 
 4324 test-convert-index-into-array-of-bytes-using-offset-on-stack:
 4325     # . prologue
 4326     55/push-ebp
 4327     89/<- %ebp 4/r32/esp
 4328     # setup
 4329     (clear-stream _test-input-stream)
 4330     (clear-stream $_test-input-buffered-file->buffer)
 4331     (clear-stream _test-output-stream)
 4332     (clear-stream $_test-output-buffered-file->buffer)
 4333     #
 4334     (write _test-input-stream "fn foo {\n")
 4335     (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
 4336     (write _test-input-stream "  var idx: int\n")
 4337     (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
 4338     (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
 4339     (write _test-input-stream "}\n")
 4340     # convert
 4341     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4342     (flush _test-output-buffered-file)
 4343 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4349     # check output
 4350     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
 4351     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
 4352     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
 4353     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/3")
 4354     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
 4355     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
 4356     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/6")
 4357     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/7")
 4358     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/8")
 4359     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/9")
 4360     (check-next-stream-line-equal _test-output-stream "    69/multiply *(ebp+0xfffffff8) 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/10")
 4361     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
 4362     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
 4363     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
 4364     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
 4365     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
 4366     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
 4367     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
 4368     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
 4369     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
 4370     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
 4371     # . epilogue
 4372     89/<- %esp 5/r32/ebp
 4373     5d/pop-to-ebp
 4374     c3/return
 4375 
 4376 test-convert-function-and-type-definition:
 4377     # . prologue
 4378     55/push-ebp
 4379     89/<- %ebp 4/r32/esp
 4380     # setup
 4381     (clear-stream _test-input-stream)
 4382     (clear-stream $_test-input-buffered-file->buffer)
 4383     (clear-stream _test-output-stream)
 4384     (clear-stream $_test-output-buffered-file->buffer)
 4385     #
 4386     (write _test-input-stream "fn foo a: (addr t) {\n")
 4387     (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
 4388     (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
 4389     (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
 4390     (write _test-input-stream "}\n")
 4391     (write _test-input-stream "type t {\n")
 4392     (write _test-input-stream "  x: int\n")
 4393     (write _test-input-stream "  y: int\n")
 4394     (write _test-input-stream "}\n")
 4395     # convert
 4396     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4397     (flush _test-output-buffered-file)
 4398 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4404     # check output
 4405     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
 4406     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
 4407     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
 4408     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
 4409     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
 4410     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
 4411     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
 4412     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
 4413     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
 4414     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
 4415     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
 4416     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
 4417     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
 4418     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
 4419     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
 4420     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
 4421     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
 4422     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
 4423     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
 4424     # . epilogue
 4425     89/<- %esp 5/r32/ebp
 4426     5d/pop-to-ebp
 4427     c3/return
 4428 
 4429 test-convert-function-with-local-var-with-user-defined-type:
 4430     # . prologue
 4431     55/push-ebp
 4432     89/<- %ebp 4/r32/esp
 4433     # setup
 4434     (clear-stream _test-input-stream)
 4435     (clear-stream $_test-input-buffered-file->buffer)
 4436     (clear-stream _test-output-stream)
 4437     (clear-stream $_test-output-buffered-file->buffer)
 4438     #
 4439     (write _test-input-stream "fn foo {\n")
 4440     (write _test-input-stream "  var a: t\n")
 4441     (write _test-input-stream "}\n")
 4442     (write _test-input-stream "type t {\n")
 4443     (write _test-input-stream "  x: int\n")
 4444     (write _test-input-stream "  y: int\n")
 4445     (write _test-input-stream "}\n")
 4446     # convert
 4447     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4448     (flush _test-output-buffered-file)
 4449 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4455     # check output
 4456     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
 4457     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
 4458     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
 4459     (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")
 4460     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
 4461     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
 4462     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
 4463     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
 4464     (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")
 4465     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
 4466     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
 4467     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
 4468     (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")
 4469     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
 4470     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
 4471     # . epilogue
 4472     89/<- %esp 5/r32/ebp
 4473     5d/pop-to-ebp
 4474     c3/return
 4475 
 4476 test-convert-function-call-with-arg-of-user-defined-type:
 4477     # . prologue
 4478     55/push-ebp
 4479     89/<- %ebp 4/r32/esp
 4480     # setup
 4481     (clear-stream _test-input-stream)
 4482     (clear-stream $_test-input-buffered-file->buffer)
 4483     (clear-stream _test-output-stream)
 4484     (clear-stream $_test-output-buffered-file->buffer)
 4485     #
 4486     (write _test-input-stream "fn f {\n")
 4487     (write _test-input-stream "  var a: t\n")
 4488     (write _test-input-stream "  foo a\n")
 4489     (write _test-input-stream "}\n")
 4490     (write _test-input-stream "fn foo x: t {\n")
 4491     (write _test-input-stream "}\n")
 4492     (write _test-input-stream "type t {\n")
 4493     (write _test-input-stream "  x: int\n")
 4494     (write _test-input-stream "  y: int\n")
 4495     (write _test-input-stream "}\n")
 4496     # convert
 4497     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4498     (flush _test-output-buffered-file)
 4499 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4505     # check output
 4506     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4507     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4508     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4509     (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")
 4510     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4511     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4512     # var a: t
 4513     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
 4514     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
 4515     # foo a
 4516     (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")
 4517     #
 4518     (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")
 4519     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4520     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4521     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4522     (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")
 4523     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4524     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4525     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4526     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4527     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4528     (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")
 4529     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4530     (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")
 4531     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4532     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4533     # . epilogue
 4534     89/<- %esp 5/r32/ebp
 4535     5d/pop-to-ebp
 4536     c3/return
 4537 
 4538 test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
 4539     # . prologue
 4540     55/push-ebp
 4541     89/<- %ebp 4/r32/esp
 4542     # setup
 4543     (clear-stream _test-input-stream)
 4544     (clear-stream $_test-input-buffered-file->buffer)
 4545     (clear-stream _test-output-stream)
 4546     (clear-stream $_test-output-buffered-file->buffer)
 4547     #
 4548     (write _test-input-stream "fn f {\n")
 4549     (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
 4550     (write _test-input-stream "  foo *a\n")
 4551     (write _test-input-stream "}\n")
 4552     (write _test-input-stream "fn foo x: t {\n")
 4553     (write _test-input-stream "}\n")
 4554     (write _test-input-stream "type t {\n")
 4555     (write _test-input-stream "  x: int\n")
 4556     (write _test-input-stream "  y: int\n")
 4557     (write _test-input-stream "}\n")
 4558     # convert
 4559     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4560     (flush _test-output-buffered-file)
 4561 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4567     # check output
 4568     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
 4569     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
 4570     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
 4571     (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")
 4572     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
 4573     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
 4574     # var a
 4575     (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")
 4576     (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")
 4577     # foo a
 4578     (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")
 4579     #
 4580     (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")
 4581     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
 4582     (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
 4583     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
 4584     (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")
 4585     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
 4586     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
 4587     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
 4588     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
 4589     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
 4590     (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")
 4591     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
 4592     (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")
 4593     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
 4594     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
 4595     # . epilogue
 4596     89/<- %esp 5/r32/ebp
 4597     5d/pop-to-ebp
 4598     c3/return
 4599 
 4600 # we don't have special support for call-by-reference; just explicitly create
 4601 # a new variable with the address of the arg
 4602 test-convert-function-call-with-arg-of-user-defined-type-by-reference:
 4603     # . prologue
 4604     55/push-ebp
 4605     89/<- %ebp 4/r32/esp
 4606     # setup
 4607     (clear-stream _test-input-stream)
 4608     (clear-stream $_test-input-buffered-file->buffer)
 4609     (clear-stream _test-output-stream)
 4610     (clear-stream $_test-output-buffered-file->buffer)
 4611     #
 4612     (write _test-input-stream "fn f {\n")
 4613     (write _test-input-stream "  var a: t\n")
 4614     (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
 4615     (write _test-input-stream "  foo b\n")
 4616     (write _test-input-stream "}\n")
 4617     (write _test-input-stream "fn foo x: (addr t) {\n")
 4618     (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
 4619     (write _test-input-stream "  increment *x\n")
 4620     (write _test-input-stream "}\n")
 4621     (write _test-input-stream "type t {\n")
 4622     (write _test-input-stream "  x: int\n")
 4623     (write _test-input-stream "  y: int\n")
 4624     (write _test-input-stream "}\n")
 4625     # convert
 4626     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4627     (flush _test-output-buffered-file)
 4628 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4634     # check output
 4635     (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
 4636     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
 4637     (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")
 4638     (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")
 4639     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
 4640     (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")
 4641     # var a: t
 4642     (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")
 4643     (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")
 4644     # var b/eax: (addr t)
 4645     (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")
 4646     (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")
 4647     # foo a
 4648     (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
 4649     #
 4650     (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")
 4651     (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")
 4652     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
 4653     (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")
 4654     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
 4655     (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")
 4656     (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")
 4657     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
 4658     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
 4659     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
 4660     (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")
 4661     (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")
 4662     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
 4663     (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")
 4664     (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")
 4665     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000001/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26")
 4666     (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")
 4667     (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")
 4668     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
 4669     (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")
 4670     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
 4671     (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")
 4672     (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")
 4673     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
 4674     # . epilogue
 4675     89/<- %esp 5/r32/ebp
 4676     5d/pop-to-ebp
 4677     c3/return
 4678 
 4679 test-convert-get-on-local-variable:
 4680     # . prologue
 4681     55/push-ebp
 4682     89/<- %ebp 4/r32/esp
 4683     # setup
 4684     (clear-stream _test-input-stream)
 4685     (clear-stream $_test-input-buffered-file->buffer)
 4686     (clear-stream _test-output-stream)
 4687     (clear-stream $_test-output-buffered-file->buffer)
 4688     #
 4689     (write _test-input-stream "fn foo {\n")
 4690     (write _test-input-stream "  var a: t\n")
 4691     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4692     (write _test-input-stream "}\n")
 4693     (write _test-input-stream "type t {\n")
 4694     (write _test-input-stream "  x: int\n")
 4695     (write _test-input-stream "  y: int\n")
 4696     (write _test-input-stream "}\n")
 4697     # convert
 4698     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4699     (flush _test-output-buffered-file)
 4700 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4706     # check output
 4707     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
 4708     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
 4709     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
 4710     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
 4711     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
 4712     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
 4713     # var a
 4714     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
 4715     (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
 4716     # var c
 4717     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
 4718     # get
 4719     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
 4720     # reclaim c
 4721     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
 4722     # reclaim a
 4723     (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
 4724     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
 4725     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
 4726     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
 4727     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
 4728     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
 4729     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
 4730     # . epilogue
 4731     89/<- %esp 5/r32/ebp
 4732     5d/pop-to-ebp
 4733     c3/return
 4734 
 4735 test-convert-get-on-function-argument:
 4736     # . prologue
 4737     55/push-ebp
 4738     89/<- %ebp 4/r32/esp
 4739     # setup
 4740     (clear-stream _test-input-stream)
 4741     (clear-stream $_test-input-buffered-file->buffer)
 4742     (clear-stream _test-output-stream)
 4743     (clear-stream $_test-output-buffered-file->buffer)
 4744     #
 4745     (write _test-input-stream "fn foo a: t {\n")
 4746     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4747     (write _test-input-stream "}\n")
 4748     (write _test-input-stream "type t {\n")
 4749     (write _test-input-stream "  x: int\n")
 4750     (write _test-input-stream "  y: int\n")
 4751     (write _test-input-stream "}\n")
 4752     # convert
 4753     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4754     (flush _test-output-buffered-file)
 4755 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4761     # check output
 4762     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
 4763     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
 4764     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
 4765     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
 4766     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
 4767     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
 4768     # var c
 4769     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
 4770     # get
 4771     (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
 4772     # reclaim c
 4773     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
 4774     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
 4775     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
 4776     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
 4777     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
 4778     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
 4779     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
 4780     # . epilogue
 4781     89/<- %esp 5/r32/ebp
 4782     5d/pop-to-ebp
 4783     c3/return
 4784 
 4785 test-convert-get-on-function-argument-with-known-type:
 4786     # . prologue
 4787     55/push-ebp
 4788     89/<- %ebp 4/r32/esp
 4789     # setup
 4790     (clear-stream _test-input-stream)
 4791     (clear-stream $_test-input-buffered-file->buffer)
 4792     (clear-stream _test-output-stream)
 4793     (clear-stream $_test-output-buffered-file->buffer)
 4794     #
 4795     (write _test-input-stream "type t {\n")
 4796     (write _test-input-stream "  x: int\n")
 4797     (write _test-input-stream "  y: int\n")
 4798     (write _test-input-stream "}\n")
 4799     (write _test-input-stream "fn foo a: t {\n")
 4800     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 4801     (write _test-input-stream "}\n")
 4802     # convert
 4803     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 4804     (flush _test-output-buffered-file)
 4805 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 4811     # check output
 4812     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
 4813     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
 4814     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
 4815     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
 4816     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
 4817     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
 4818     # var c
 4819     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
 4820     # get
 4821     (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")
 4822     # reclaim c
 4823     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
 4824     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
 4825     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
 4826     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
 4827     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
 4828     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
 4829     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
 4830     # . epilogue
 4831     89/<- %esp 5/r32/ebp
 4832     5d/pop-to-ebp
 4833     c3/return
 4834 
 4835 test-add-with-too-many-inouts:
 4836     # . prologue
 4837     55/push-ebp
 4838     89/<- %ebp 4/r32/esp
 4839     # setup
 4840     (clear-stream _test-input-stream)
 4841     (clear-stream $_test-input-buffered-file->buffer)
 4842     (clear-stream _test-output-stream)
 4843     (clear-stream $_test-output-buffered-file->buffer)
 4844     (clear-stream _test-error-stream)
 4845     (clear-stream $_test-error-buffered-file->buffer)
 4846     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4847     68/push 0/imm32
 4848     68/push 0/imm32
 4849     89/<- %edx 4/r32/esp
 4850     (tailor-exit-descriptor %edx 0x10)
 4851     #
 4852     (write _test-input-stream "fn foo {\n")
 4853     (write _test-input-stream "  var a: int\n")
 4854     (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
 4855     (write _test-input-stream "}\n")
 4856     # convert
 4857     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4858     # registers except esp clobbered at this point
 4859     # restore ed
 4860     89/<- %edx 4/r32/esp
 4861     (flush _test-output-buffered-file)
 4862     (flush _test-error-buffered-file)
 4863 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4869     # check output
 4870     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
 4871     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts: error message")
 4872     # check that stop(1) was called
 4873     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
 4874     # don't restore from ebp
 4875     81 0/subop/add %esp 8/imm32
 4876     # . epilogue
 4877     5d/pop-to-ebp
 4878     c3/return
 4879 
 4880 test-add-with-too-many-inouts-2:
 4881     # . prologue
 4882     55/push-ebp
 4883     89/<- %ebp 4/r32/esp
 4884     # setup
 4885     (clear-stream _test-input-stream)
 4886     (clear-stream $_test-input-buffered-file->buffer)
 4887     (clear-stream _test-output-stream)
 4888     (clear-stream $_test-output-buffered-file->buffer)
 4889     (clear-stream _test-error-stream)
 4890     (clear-stream $_test-error-buffered-file->buffer)
 4891     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4892     68/push 0/imm32
 4893     68/push 0/imm32
 4894     89/<- %edx 4/r32/esp
 4895     (tailor-exit-descriptor %edx 0x10)
 4896     #
 4897     (write _test-input-stream "fn foo {\n")
 4898     (write _test-input-stream "  var a: int\n")
 4899     (write _test-input-stream "  add-to a, 0, 1\n")
 4900     (write _test-input-stream "}\n")
 4901     # convert
 4902     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4903     # registers except esp clobbered at this point
 4904     # restore ed
 4905     89/<- %edx 4/r32/esp
 4906     (flush _test-output-buffered-file)
 4907     (flush _test-error-buffered-file)
 4908 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4914     # check output
 4915     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
 4916     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add-to: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts-2: error message")
 4917     # check that stop(1) was called
 4918     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
 4919     # don't restore from ebp
 4920     81 0/subop/add %esp 8/imm32
 4921     # . epilogue
 4922     5d/pop-to-ebp
 4923     c3/return
 4924 
 4925 test-add-with-too-many-outputs:
 4926     # . prologue
 4927     55/push-ebp
 4928     89/<- %ebp 4/r32/esp
 4929     # setup
 4930     (clear-stream _test-input-stream)
 4931     (clear-stream $_test-input-buffered-file->buffer)
 4932     (clear-stream _test-output-stream)
 4933     (clear-stream $_test-output-buffered-file->buffer)
 4934     (clear-stream _test-error-stream)
 4935     (clear-stream $_test-error-buffered-file->buffer)
 4936     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4937     68/push 0/imm32
 4938     68/push 0/imm32
 4939     89/<- %edx 4/r32/esp
 4940     (tailor-exit-descriptor %edx 0x10)
 4941     #
 4942     (write _test-input-stream "fn foo {\n")
 4943     (write _test-input-stream "  var a/eax: int <- copy 0\n")
 4944     (write _test-input-stream "  var b/ebx: int <- copy 0\n")
 4945     (write _test-input-stream "  var c/ecx: int <- copy 0\n")
 4946     (write _test-input-stream "  c, b <- add a\n")
 4947     (write _test-input-stream "}\n")
 4948     # convert
 4949     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4950     # registers except esp clobbered at this point
 4951     # restore ed
 4952     89/<- %edx 4/r32/esp
 4953     (flush _test-output-buffered-file)
 4954     (flush _test-error-buffered-file)
 4955 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 4961     # check output
 4962     (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
 4963     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many outputs; most primitives support at most one output"  "F - test-add-with-too-many-outputs: error message")
 4964     # check that stop(1) was called
 4965     (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
 4966     # don't restore from ebp
 4967     81 0/subop/add %esp 8/imm32
 4968     # . epilogue
 4969     5d/pop-to-ebp
 4970     c3/return
 4971 
 4972 test-add-with-non-number:
 4973     # . prologue
 4974     55/push-ebp
 4975     89/<- %ebp 4/r32/esp
 4976     # setup
 4977     (clear-stream _test-input-stream)
 4978     (clear-stream $_test-input-buffered-file->buffer)
 4979     (clear-stream _test-output-stream)
 4980     (clear-stream $_test-output-buffered-file->buffer)
 4981     (clear-stream _test-error-stream)
 4982     (clear-stream $_test-error-buffered-file->buffer)
 4983     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 4984     68/push 0/imm32
 4985     68/push 0/imm32
 4986     89/<- %edx 4/r32/esp
 4987     (tailor-exit-descriptor %edx 0x10)
 4988     #
 4989     (write _test-input-stream "fn foo {\n")
 4990     (write _test-input-stream "  var a: int\n")
 4991     (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
 4992     (write _test-input-stream "}\n")
 4993     # convert
 4994     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 4995     # registers except esp clobbered at this point
 4996     # restore ed
 4997     89/<- %edx 4/r32/esp
 4998     (flush _test-output-buffered-file)
 4999     (flush _test-error-buffered-file)
 5000 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5006     # check output
 5007     (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
 5008     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: only non-addr scalar args permitted"  "F - test-add-with-non-number: error message")
 5009     # check that stop(1) was called
 5010     (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
 5011     # don't restore from ebp
 5012     81 0/subop/add %esp 8/imm32
 5013     # . epilogue
 5014     5d/pop-to-ebp
 5015     c3/return
 5016 
 5017 test-add-with-addr-dereferenced:
 5018     # . prologue
 5019     55/push-ebp
 5020     89/<- %ebp 4/r32/esp
 5021     # setup
 5022     (clear-stream _test-input-stream)
 5023     (clear-stream $_test-input-buffered-file->buffer)
 5024     (clear-stream _test-output-stream)
 5025     (clear-stream $_test-output-buffered-file->buffer)
 5026     #
 5027     (write _test-input-stream "fn foo {\n")
 5028     (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
 5029     (write _test-input-stream "  add-to *a, 1\n")
 5030     (write _test-input-stream "}\n")
 5031     # convert
 5032     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5033     (flush _test-output-buffered-file)
 5034     # no error
 5035     # . epilogue
 5036     89/<- %esp 5/r32/ebp
 5037     5d/pop-to-ebp
 5038     c3/return
 5039 
 5040 test-get-with-wrong-field:
 5041     # . prologue
 5042     55/push-ebp
 5043     89/<- %ebp 4/r32/esp
 5044     # setup
 5045     (clear-stream _test-input-stream)
 5046     (clear-stream $_test-input-buffered-file->buffer)
 5047     (clear-stream _test-output-stream)
 5048     (clear-stream $_test-output-buffered-file->buffer)
 5049     (clear-stream _test-error-stream)
 5050     (clear-stream $_test-error-buffered-file->buffer)
 5051     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5052     68/push 0/imm32
 5053     68/push 0/imm32
 5054     89/<- %edx 4/r32/esp
 5055     (tailor-exit-descriptor %edx 0x10)
 5056     #
 5057     (write _test-input-stream "fn foo {\n")
 5058     (write _test-input-stream "  var a: t\n")
 5059     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5060     (write _test-input-stream "}\n")
 5061     (write _test-input-stream "type t {\n")
 5062     (write _test-input-stream "  x: int\n")
 5063     (write _test-input-stream "}\n")
 5064     # convert
 5065     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5066     # registers except esp clobbered at this point
 5067     # restore ed
 5068     89/<- %edx 4/r32/esp
 5069     (flush _test-output-buffered-file)
 5070     (flush _test-error-buffered-file)
 5071 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5077     # check output
 5078     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
 5079     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
 5080     # check that stop(1) was called
 5081     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
 5082     # don't restore from ebp
 5083     81 0/subop/add %esp 8/imm32
 5084     # . epilogue
 5085     5d/pop-to-ebp
 5086     c3/return
 5087 
 5088 test-get-with-wrong-base-type:
 5089     # . prologue
 5090     55/push-ebp
 5091     89/<- %ebp 4/r32/esp
 5092     # setup
 5093     (clear-stream _test-input-stream)
 5094     (clear-stream $_test-input-buffered-file->buffer)
 5095     (clear-stream _test-output-stream)
 5096     (clear-stream $_test-output-buffered-file->buffer)
 5097     (clear-stream _test-error-stream)
 5098     (clear-stream $_test-error-buffered-file->buffer)
 5099     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5100     68/push 0/imm32
 5101     68/push 0/imm32
 5102     89/<- %edx 4/r32/esp
 5103     (tailor-exit-descriptor %edx 0x10)
 5104     #
 5105     (write _test-input-stream "fn foo {\n")
 5106     (write _test-input-stream "  var a: int\n")
 5107     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5108     (write _test-input-stream "}\n")
 5109     # convert
 5110     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5111     # registers except esp clobbered at this point
 5112     # restore ed
 5113     89/<- %edx 4/r32/esp
 5114     (flush _test-output-buffered-file)
 5115     (flush _test-error-buffered-file)
 5116 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5122     # check output
 5123     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
 5124     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' must have a 'type' definition"  "F - test-get-with-wrong-base-type: error message")
 5125     # check that stop(1) was called
 5126     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
 5127     # don't restore from ebp
 5128     81 0/subop/add %esp 8/imm32
 5129     # . epilogue
 5130     5d/pop-to-ebp
 5131     c3/return
 5132 
 5133 test-get-with-wrong-base-type-2:
 5134     # . prologue
 5135     55/push-ebp
 5136     89/<- %ebp 4/r32/esp
 5137     # setup
 5138     (clear-stream _test-input-stream)
 5139     (clear-stream $_test-input-buffered-file->buffer)
 5140     (clear-stream _test-output-stream)
 5141     (clear-stream $_test-output-buffered-file->buffer)
 5142     (clear-stream _test-error-stream)
 5143     (clear-stream $_test-error-buffered-file->buffer)
 5144     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5145     68/push 0/imm32
 5146     68/push 0/imm32
 5147     89/<- %edx 4/r32/esp
 5148     (tailor-exit-descriptor %edx 0x10)
 5149     #
 5150     (write _test-input-stream "fn foo {\n")
 5151     (write _test-input-stream "  var a: (addr t)\n")
 5152     (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
 5153     (write _test-input-stream "}\n")
 5154     (write _test-input-stream "type t {\n")
 5155     (write _test-input-stream "  x: int\n")
 5156     (write _test-input-stream "}\n")
 5157     # convert
 5158     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5159     # registers except esp clobbered at this point
 5160     # restore ed
 5161     89/<- %edx 4/r32/esp
 5162     (flush _test-output-buffered-file)
 5163     (flush _test-error-buffered-file)
 5164 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5170     # check output
 5171     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
 5172     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' is an 'addr' type, and so must live in a register"  "F - test-get-with-wrong-base-type-2: error message")
 5173     # check that stop(1) was called
 5174     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
 5175     # don't restore from ebp
 5176     81 0/subop/add %esp 8/imm32
 5177     # . epilogue
 5178     5d/pop-to-ebp
 5179     c3/return
 5180 
 5181 test-get-with-wrong-offset-type:
 5182     # . prologue
 5183     55/push-ebp
 5184     89/<- %ebp 4/r32/esp
 5185     # setup
 5186     (clear-stream _test-input-stream)
 5187     (clear-stream $_test-input-buffered-file->buffer)
 5188     (clear-stream _test-output-stream)
 5189     (clear-stream $_test-output-buffered-file->buffer)
 5190     (clear-stream _test-error-stream)
 5191     (clear-stream $_test-error-buffered-file->buffer)
 5192     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5193     68/push 0/imm32
 5194     68/push 0/imm32
 5195     89/<- %edx 4/r32/esp
 5196     (tailor-exit-descriptor %edx 0x10)
 5197     #
 5198     (write _test-input-stream "fn foo {\n")
 5199     (write _test-input-stream "  var a: t\n")
 5200     (write _test-input-stream "  var b: int\n")
 5201     (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
 5202     (write _test-input-stream "}\n")
 5203     (write _test-input-stream "type t {\n")
 5204     (write _test-input-stream "  x: int\n")
 5205     (write _test-input-stream "}\n")
 5206     # convert
 5207     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5208     # registers except esp clobbered at this point
 5209     # restore ed
 5210     89/<- %edx 4/r32/esp
 5211     (flush _test-output-buffered-file)
 5212     (flush _test-error-buffered-file)
 5213 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5219     # check output
 5220     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
 5221     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'b'"  "F - test-get-with-wrong-offset-type: error message")
 5222     # check that stop(1) was called
 5223     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
 5224     # don't restore from ebp
 5225     81 0/subop/add %esp 8/imm32
 5226     # . epilogue
 5227     5d/pop-to-ebp
 5228     c3/return
 5229 
 5230 test-get-with-wrong-output-type:
 5231     # . prologue
 5232     55/push-ebp
 5233     89/<- %ebp 4/r32/esp
 5234     # setup
 5235     (clear-stream _test-input-stream)
 5236     (clear-stream $_test-input-buffered-file->buffer)
 5237     (clear-stream _test-output-stream)
 5238     (clear-stream $_test-output-buffered-file->buffer)
 5239     (clear-stream _test-error-stream)
 5240     (clear-stream $_test-error-buffered-file->buffer)
 5241     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5242     68/push 0/imm32
 5243     68/push 0/imm32
 5244     89/<- %edx 4/r32/esp
 5245     (tailor-exit-descriptor %edx 0x10)
 5246     #
 5247     (write _test-input-stream "fn foo {\n")
 5248     (write _test-input-stream "  var a: t\n")
 5249     (write _test-input-stream "  var c: (addr int)\n")
 5250     (write _test-input-stream "  c <- get a, x\n")
 5251     (write _test-input-stream "}\n")
 5252     (write _test-input-stream "type t {\n")
 5253     (write _test-input-stream "  x: int\n")
 5254     (write _test-input-stream "}\n")
 5255     # convert
 5256     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5257     # registers except esp clobbered at this point
 5258     # restore ed
 5259     89/<- %edx 4/r32/esp
 5260     (flush _test-output-buffered-file)
 5261     (flush _test-error-buffered-file)
 5262 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5268     # check output
 5269     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
 5270     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output 'c' is not in a register"  "F - test-get-with-wrong-output-type: error message")
 5271     # check that stop(1) was called
 5272     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
 5273     # don't restore from ebp
 5274     81 0/subop/add %esp 8/imm32
 5275     # . epilogue
 5276     5d/pop-to-ebp
 5277     c3/return
 5278 
 5279 test-get-with-wrong-output-type-2:
 5280     # . prologue
 5281     55/push-ebp
 5282     89/<- %ebp 4/r32/esp
 5283     # setup
 5284     (clear-stream _test-input-stream)
 5285     (clear-stream $_test-input-buffered-file->buffer)
 5286     (clear-stream _test-output-stream)
 5287     (clear-stream $_test-output-buffered-file->buffer)
 5288     (clear-stream _test-error-stream)
 5289     (clear-stream $_test-error-buffered-file->buffer)
 5290     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5291     68/push 0/imm32
 5292     68/push 0/imm32
 5293     89/<- %edx 4/r32/esp
 5294     (tailor-exit-descriptor %edx 0x10)
 5295     #
 5296     (write _test-input-stream "fn foo {\n")
 5297     (write _test-input-stream "  var a: t\n")
 5298     (write _test-input-stream "  var c/ecx: int <- get a, x\n")
 5299     (write _test-input-stream "}\n")
 5300     (write _test-input-stream "type t {\n")
 5301     (write _test-input-stream "  x: int\n")
 5302     (write _test-input-stream "}\n")
 5303     # convert
 5304     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5305     # registers except esp clobbered at this point
 5306     # restore ed
 5307     89/<- %edx 4/r32/esp
 5308     (flush _test-output-buffered-file)
 5309     (flush _test-error-buffered-file)
 5310 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5316     # check output
 5317     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
 5318     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-2: error message")
 5319     # check that stop(1) was called
 5320     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
 5321     # don't restore from ebp
 5322     81 0/subop/add %esp 8/imm32
 5323     # . epilogue
 5324     5d/pop-to-ebp
 5325     c3/return
 5326 
 5327 test-get-with-wrong-output-type-3:
 5328     # . prologue
 5329     55/push-ebp
 5330     89/<- %ebp 4/r32/esp
 5331     # setup
 5332     (clear-stream _test-input-stream)
 5333     (clear-stream $_test-input-buffered-file->buffer)
 5334     (clear-stream _test-output-stream)
 5335     (clear-stream $_test-output-buffered-file->buffer)
 5336     (clear-stream _test-error-stream)
 5337     (clear-stream $_test-error-buffered-file->buffer)
 5338     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5339     68/push 0/imm32
 5340     68/push 0/imm32
 5341     89/<- %edx 4/r32/esp
 5342     (tailor-exit-descriptor %edx 0x10)
 5343     #
 5344     (write _test-input-stream "fn foo {\n")
 5345     (write _test-input-stream "  var a: t\n")
 5346     (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
 5347     (write _test-input-stream "}\n")
 5348     (write _test-input-stream "type t {\n")
 5349     (write _test-input-stream "  x: int\n")
 5350     (write _test-input-stream "}\n")
 5351     # convert
 5352     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5353     # registers except esp clobbered at this point
 5354     # restore ed
 5355     89/<- %edx 4/r32/esp
 5356     (flush _test-output-buffered-file)
 5357     (flush _test-error-buffered-file)
 5358 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5364     # check output
 5365     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
 5366     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-3: error message")
 5367     # check that stop(1) was called
 5368     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
 5369     # don't restore from ebp
 5370     81 0/subop/add %esp 8/imm32
 5371     # . epilogue
 5372     5d/pop-to-ebp
 5373     c3/return
 5374 
 5375 test-get-with-wrong-output-type-4:
 5376     # . prologue
 5377     55/push-ebp
 5378     89/<- %ebp 4/r32/esp
 5379     # setup
 5380     (clear-stream _test-input-stream)
 5381     (clear-stream $_test-input-buffered-file->buffer)
 5382     (clear-stream _test-output-stream)
 5383     (clear-stream $_test-output-buffered-file->buffer)
 5384     (clear-stream _test-error-stream)
 5385     (clear-stream $_test-error-buffered-file->buffer)
 5386     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5387     68/push 0/imm32
 5388     68/push 0/imm32
 5389     89/<- %edx 4/r32/esp
 5390     (tailor-exit-descriptor %edx 0x10)
 5391     #
 5392     (write _test-input-stream "fn foo {\n")
 5393     (write _test-input-stream "  var a: t\n")
 5394     (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
 5395     (write _test-input-stream "}\n")
 5396     (write _test-input-stream "type t {\n")
 5397     (write _test-input-stream "  x: int\n")
 5398     (write _test-input-stream "}\n")
 5399     # convert
 5400     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5401     # registers except esp clobbered at this point
 5402     # restore ed
 5403     89/<- %edx 4/r32/esp
 5404     (flush _test-output-buffered-file)
 5405     (flush _test-error-buffered-file)
 5406 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5412     # check output
 5413     (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
 5414     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: wrong output type for member 'x' of type 't'"  "F - test-get-with-wrong-output-type-4: error message")
 5415     # check that stop(1) was called
 5416     (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
 5417     # don't restore from ebp
 5418     81 0/subop/add %esp 8/imm32
 5419     # . epilogue
 5420     5d/pop-to-ebp
 5421     c3/return
 5422 
 5423 test-get-with-wrong-output-type-5:
 5424     # . prologue
 5425     55/push-ebp
 5426     89/<- %ebp 4/r32/esp
 5427     # setup
 5428     (clear-stream _test-input-stream)
 5429     (clear-stream $_test-input-buffered-file->buffer)
 5430     (clear-stream _test-output-stream)
 5431     (clear-stream $_test-output-buffered-file->buffer)
 5432     #
 5433     (write _test-input-stream "fn foo {\n")
 5434     (write _test-input-stream "  var a: t\n")
 5435     (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
 5436     (write _test-input-stream "}\n")
 5437     (write _test-input-stream "type t {\n")
 5438     (write _test-input-stream "  x: (handle int)\n")
 5439     (write _test-input-stream "}\n")
 5440     # convert
 5441     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5442     (flush _test-output-buffered-file)
 5443     # no errors
 5444     # . epilogue
 5445     89/<- %esp 5/r32/ebp
 5446     5d/pop-to-ebp
 5447     c3/return
 5448 
 5449 test-get-with-too-few-inouts:
 5450     # . prologue
 5451     55/push-ebp
 5452     89/<- %ebp 4/r32/esp
 5453     # setup
 5454     (clear-stream _test-input-stream)
 5455     (clear-stream $_test-input-buffered-file->buffer)
 5456     (clear-stream _test-output-stream)
 5457     (clear-stream $_test-output-buffered-file->buffer)
 5458     (clear-stream _test-error-stream)
 5459     (clear-stream $_test-error-buffered-file->buffer)
 5460     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5461     68/push 0/imm32
 5462     68/push 0/imm32
 5463     89/<- %edx 4/r32/esp
 5464     (tailor-exit-descriptor %edx 0x10)
 5465     #
 5466     (write _test-input-stream "fn foo {\n")
 5467     (write _test-input-stream "  var a: t\n")
 5468     (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
 5469     (write _test-input-stream "}\n")
 5470     (write _test-input-stream "type t {\n")
 5471     (write _test-input-stream "  x: int\n")
 5472     (write _test-input-stream "}\n")
 5473     # convert
 5474     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5475     # registers except esp clobbered at this point
 5476     # restore ed
 5477     89/<- %edx 4/r32/esp
 5478     (flush _test-output-buffered-file)
 5479     (flush _test-error-buffered-file)
 5480 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5486     # check output
 5487     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
 5488     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too few inouts (2 required)"  "F - test-get-with-too-few-inouts: error message")
 5489     # check that stop(1) was called
 5490     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
 5491     # don't restore from ebp
 5492     81 0/subop/add %esp 8/imm32
 5493     # . epilogue
 5494     5d/pop-to-ebp
 5495     c3/return
 5496 
 5497 test-get-with-too-many-inouts:
 5498     # . prologue
 5499     55/push-ebp
 5500     89/<- %ebp 4/r32/esp
 5501     # setup
 5502     (clear-stream _test-input-stream)
 5503     (clear-stream $_test-input-buffered-file->buffer)
 5504     (clear-stream _test-output-stream)
 5505     (clear-stream $_test-output-buffered-file->buffer)
 5506     (clear-stream _test-error-stream)
 5507     (clear-stream $_test-error-buffered-file->buffer)
 5508     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5509     68/push 0/imm32
 5510     68/push 0/imm32
 5511     89/<- %edx 4/r32/esp
 5512     (tailor-exit-descriptor %edx 0x10)
 5513     #
 5514     (write _test-input-stream "fn foo {\n")
 5515     (write _test-input-stream "  var a: t\n")
 5516     (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
 5517     (write _test-input-stream "}\n")
 5518     (write _test-input-stream "type t {\n")
 5519     (write _test-input-stream "  x: int\n")
 5520     (write _test-input-stream "}\n")
 5521     # convert
 5522     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5523     # registers except esp clobbered at this point
 5524     # restore ed
 5525     89/<- %edx 4/r32/esp
 5526     (flush _test-output-buffered-file)
 5527     (flush _test-error-buffered-file)
 5528 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5534     # check output
 5535     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
 5536     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many inouts (2 required)"  "F - test-get-with-too-many-inouts: error message")
 5537     # check that stop(1) was called
 5538     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
 5539     # don't restore from ebp
 5540     81 0/subop/add %esp 8/imm32
 5541     # . epilogue
 5542     5d/pop-to-ebp
 5543     c3/return
 5544 
 5545 test-get-with-no-output:
 5546     # . prologue
 5547     55/push-ebp
 5548     89/<- %ebp 4/r32/esp
 5549     # setup
 5550     (clear-stream _test-input-stream)
 5551     (clear-stream $_test-input-buffered-file->buffer)
 5552     (clear-stream _test-output-stream)
 5553     (clear-stream $_test-output-buffered-file->buffer)
 5554     (clear-stream _test-error-stream)
 5555     (clear-stream $_test-error-buffered-file->buffer)
 5556     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5557     68/push 0/imm32
 5558     68/push 0/imm32
 5559     89/<- %edx 4/r32/esp
 5560     (tailor-exit-descriptor %edx 0x10)
 5561     #
 5562     (write _test-input-stream "fn foo {\n")
 5563     (write _test-input-stream "  var a: t\n")
 5564     (write _test-input-stream "  get a, x\n")
 5565     (write _test-input-stream "}\n")
 5566     (write _test-input-stream "type t {\n")
 5567     (write _test-input-stream "  x: int\n")
 5568     (write _test-input-stream "}\n")
 5569     # convert
 5570     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5571     # registers except esp clobbered at this point
 5572     # restore ed
 5573     89/<- %edx 4/r32/esp
 5574     (flush _test-output-buffered-file)
 5575     (flush _test-error-buffered-file)
 5576 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5582     # check output
 5583     (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
 5584     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
 5585     # check that stop(1) was called
 5586     (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
 5587     # don't restore from ebp
 5588     81 0/subop/add %esp 8/imm32
 5589     # . epilogue
 5590     5d/pop-to-ebp
 5591     c3/return
 5592 
 5593 test-get-with-too-many-outputs:
 5594     # . prologue
 5595     55/push-ebp
 5596     89/<- %ebp 4/r32/esp
 5597     # setup
 5598     (clear-stream _test-input-stream)
 5599     (clear-stream $_test-input-buffered-file->buffer)
 5600     (clear-stream _test-output-stream)
 5601     (clear-stream $_test-output-buffered-file->buffer)
 5602     (clear-stream _test-error-stream)
 5603     (clear-stream $_test-error-buffered-file->buffer)
 5604     # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
 5605     68/push 0/imm32
 5606     68/push 0/imm32
 5607     89/<- %edx 4/r32/esp
 5608     (tailor-exit-descriptor %edx 0x10)
 5609     #
 5610     (write _test-input-stream "fn foo {\n")
 5611     (write _test-input-stream "  var a: t\n")
 5612     (write _test-input-stream "  var b: int\n")
 5613     (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
 5614     (write _test-input-stream "  c, b <- get a, x\n")
 5615     (write _test-input-stream "}\n")
 5616     (write _test-input-stream "type t {\n")
 5617     (write _test-input-stream "  x: int\n")
 5618     (write _test-input-stream "}\n")
 5619     # convert
 5620     (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
 5621     # registers except esp clobbered at this point
 5622     # restore ed
 5623     89/<- %edx 4/r32/esp
 5624     (flush _test-output-buffered-file)
 5625     (flush _test-error-buffered-file)
 5626 +--  6 lines: #?     # dump _test-error-stream ------------------------------------------------------------------------------------------------------------------------------------------
 5632     # check output
 5633     (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
 5634     (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many outputs (1 required)"  "F - test-get-with-too-many-outputs: error message")
 5635     # check that stop(1) was called
 5636     (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
 5637     # don't restore from ebp
 5638     81 0/subop/add %esp 8/imm32
 5639     # . epilogue
 5640     5d/pop-to-ebp
 5641     c3/return
 5642 
 5643 test-convert-array-of-user-defined-types:
 5644     # . prologue
 5645     55/push-ebp
 5646     89/<- %ebp 4/r32/esp
 5647     # setup
 5648     (clear-stream _test-input-stream)
 5649     (clear-stream $_test-input-buffered-file->buffer)
 5650     (clear-stream _test-output-stream)
 5651     (clear-stream $_test-output-buffered-file->buffer)
 5652     #
 5653     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 5654     (write _test-input-stream "  x: int\n")
 5655     (write _test-input-stream "  y: int\n")
 5656     (write _test-input-stream "}\n")
 5657     (write _test-input-stream "fn foo {\n")
 5658     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5659     (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
 5660     (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
 5661     (write _test-input-stream "}\n")
 5662     # convert
 5663     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5664     (flush _test-output-buffered-file)
 5665 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5671     # check output
 5672     (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
 5673     (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
 5674     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
 5675     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
 5676     (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
 5677     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
 5678     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
 5679     (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
 5680     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
 5681     (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
 5682     (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")
 5683     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
 5684     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
 5685     (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
 5686     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
 5687     (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
 5688     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
 5689     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
 5690     (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
 5691     # . epilogue
 5692     89/<- %esp 5/r32/ebp
 5693     5d/pop-to-ebp
 5694     c3/return
 5695 
 5696 test-convert-length-of-array-of-user-defined-types-to-eax:
 5697     # . prologue
 5698     55/push-ebp
 5699     89/<- %ebp 4/r32/esp
 5700     # setup
 5701     (clear-stream _test-input-stream)
 5702     (clear-stream $_test-input-buffered-file->buffer)
 5703     (clear-stream _test-output-stream)
 5704     (clear-stream $_test-output-buffered-file->buffer)
 5705     #
 5706     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5707     (write _test-input-stream "  x: int\n")
 5708     (write _test-input-stream "  y: int\n")
 5709     (write _test-input-stream "  z: int\n")
 5710     (write _test-input-stream "}\n")
 5711     (write _test-input-stream "fn foo {\n")
 5712     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5713     (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
 5714     (write _test-input-stream "}\n")
 5715     # convert
 5716     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5717     (flush _test-output-buffered-file)
 5718 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5724     # check output
 5725     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
 5726     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
 5727     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
 5728     (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")
 5729     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
 5730     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
 5731     # var arr
 5732     (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")
 5733     (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")
 5734     # length instruction
 5735     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
 5736     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
 5737     (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")
 5738     (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")
 5739     (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")
 5740     (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")
 5741     (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")
 5742     (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")
 5743     # reclaim arr
 5744     (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")
 5745     #
 5746     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
 5747     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
 5748     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
 5749     (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")
 5750     (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")
 5751     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
 5752     # . epilogue
 5753     89/<- %esp 5/r32/ebp
 5754     5d/pop-to-ebp
 5755     c3/return
 5756 
 5757 test-convert-length-of-array-of-user-defined-types-to-ecx:
 5758     # . prologue
 5759     55/push-ebp
 5760     89/<- %ebp 4/r32/esp
 5761     # setup
 5762     (clear-stream _test-input-stream)
 5763     (clear-stream $_test-input-buffered-file->buffer)
 5764     (clear-stream _test-output-stream)
 5765     (clear-stream $_test-output-buffered-file->buffer)
 5766     #
 5767     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5768     (write _test-input-stream "  x: int\n")
 5769     (write _test-input-stream "  y: int\n")
 5770     (write _test-input-stream "  z: int\n")
 5771     (write _test-input-stream "}\n")
 5772     (write _test-input-stream "fn foo {\n")
 5773     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5774     (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
 5775     (write _test-input-stream "}\n")
 5776     # convert
 5777     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5778     (flush _test-output-buffered-file)
 5779 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5785     # check output
 5786     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
 5787     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
 5788     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
 5789     (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")
 5790     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
 5791     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
 5792     # var a
 5793     (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")
 5794     (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")
 5795     # var x
 5796     (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")
 5797     # length instruction
 5798     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
 5799     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
 5800     (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")
 5801     (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")
 5802     (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")
 5803     (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")
 5804     (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")
 5805     (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")
 5806     (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")
 5807     # reclaim x
 5808     (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")
 5809     # reclaim a
 5810     (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")
 5811     #
 5812     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
 5813     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
 5814     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
 5815     (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")
 5816     (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")
 5817     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
 5818     # . epilogue
 5819     89/<- %esp 5/r32/ebp
 5820     5d/pop-to-ebp
 5821     c3/return
 5822 
 5823 test-convert-length-of-array-of-user-defined-types-to-edx:
 5824     # . prologue
 5825     55/push-ebp
 5826     89/<- %ebp 4/r32/esp
 5827     # setup
 5828     (clear-stream _test-input-stream)
 5829     (clear-stream $_test-input-buffered-file->buffer)
 5830     (clear-stream _test-output-stream)
 5831     (clear-stream $_test-output-buffered-file->buffer)
 5832     #
 5833     (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
 5834     (write _test-input-stream "  x: int\n")
 5835     (write _test-input-stream "  y: int\n")
 5836     (write _test-input-stream "  z: int\n")
 5837     (write _test-input-stream "}\n")
 5838     (write _test-input-stream "fn foo {\n")
 5839     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5840     (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
 5841     (write _test-input-stream "}\n")
 5842     # convert
 5843     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5844     (flush _test-output-buffered-file)
 5845 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5851     # check output
 5852     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
 5853     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
 5854     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
 5855     (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")
 5856     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
 5857     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
 5858     # var a
 5859     (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")
 5860     (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")
 5861     # var x
 5862     (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")
 5863     # length instruction
 5864     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
 5865     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
 5866     (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")
 5867     (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")
 5868     (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")
 5869     (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")
 5870     (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")
 5871     (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")
 5872     (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")
 5873     # reclaim x
 5874     (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")
 5875     # reclaim a
 5876     (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")
 5877     #
 5878     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
 5879     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
 5880     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
 5881     (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")
 5882     (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")
 5883     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
 5884     # . epilogue
 5885     89/<- %esp 5/r32/ebp
 5886     5d/pop-to-ebp
 5887     c3/return
 5888 
 5889 test-convert-length-of-array-of-user-defined-types:
 5890     # . prologue
 5891     55/push-ebp
 5892     89/<- %ebp 4/r32/esp
 5893     # setup
 5894     (clear-stream _test-input-stream)
 5895     (clear-stream $_test-input-buffered-file->buffer)
 5896     (clear-stream _test-output-stream)
 5897     (clear-stream $_test-output-buffered-file->buffer)
 5898     #
 5899     (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
 5900     (write _test-input-stream "  x: int\n")
 5901     (write _test-input-stream "  y: int\n")
 5902     (write _test-input-stream "  z: int\n")
 5903     (write _test-input-stream "}\n")
 5904     (write _test-input-stream "fn foo {\n")
 5905     (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
 5906     (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
 5907     (write _test-input-stream "}\n")
 5908     # convert
 5909     (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
 5910     (flush _test-output-buffered-file)
 5911 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
 5917     # check output
 5918     (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
 5919     (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
 5920     (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
 5921     (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
 5922     (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
 5923     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
 5924     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
 5925     (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")
 5926     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
 5927     (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
 5928     (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
 5929     (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
 5930     (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
 5931     (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")
 5932     (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")
 5933     (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")
 5934     (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
 5935     (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
 5936     (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
 5937     (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
 5938     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
 5939     (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
 5940     (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
 5941     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
 5942     (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
 5943     (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
 5944     (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
 5945     (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
 5946     # . epilogue
 5947     89/<- %esp 5/r32/ebp
 5948     5d/pop-to-ebp
 5949     c3/return
 5950 
 5951 #######################################################
 5952 # Parsing
 5953 #######################################################
 5954 
 5955 == data
 5956 
 5957 # Global state added to each var record when parsing a function
 5958 Next-block-index:  # (addr int)
 5959     1/imm32
 5960 
 5961 Curr-block-depth:  # (addr int)
 5962     1/imm32
 5963 
 5964 == code
 5965 
 5966 parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
 5967     # pseudocode
 5968     #   var curr-function: (addr handle function) = Program->functions
 5969     #   var curr-signature: (addr handle function) = Program->signatures
 5970     #   var curr-type: (addr handle typeinfo) = Program->types
 5971     #   var line: (stream byte 512)
 5972     #   var word-slice: slice
 5973     #   while true                                  # line loop
 5974     #     clear-stream(line)
 5975     #     read-line-buffered(in, line)
 5976     #     if (line->write == 0) break               # end of file
 5977     #     word-slice = next-mu-token(line)
 5978     #     if slice-empty?(word-slice)               # end of line
 5979     #       continue
 5980     #     else if slice-starts-with?(word-slice, "#")  # comment
 5981     #       continue                                # end of line
 5982     #     else if slice-equal?(word-slice, "fn")
 5983     #       var new-function: (handle function) = allocate(function)
 5984     #       var vars: (stack live-var 256)
 5985     #       populate-mu-function-header(line, new-function, vars)
 5986     #       populate-mu-function-body(in, new-function, vars)
 5987     #       assert(vars->top == 0)
 5988     #       *curr-function = new-function
 5989     #       curr-function = &new-function->next
 5990     #     else if slice-equal?(word-slice, "sig")
 5991     #       var new-function: (handle function) = allocate(function)
 5992     #       populate-mu-function-signature(line, new-function)
 5993     #       *curr-signature = new-function
 5994     #       curr-signature = &new-function->next
 5995     #     else if slice-equal?(word-slice, "type")
 5996     #       word-slice = next-mu-token(line)
 5997     #       type-id = pos-or-insert-slice(Type-id, word-slice)
 5998     #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
 5999     #       assert(next-word(line) == "{")
 6000     #       populate-mu-type(in, new-type)
 6001     #     else
 6002     #       abort()
 6003     #
 6004     # . prologue
 6005     55/push-ebp
 6006     89/<- %ebp 4/r32/esp
 6007     # var curr-signature: (addr handle function) at *(ebp-4)
 6008     68/push _Program-signatures/imm32
 6009     # . save registers
 6010     50/push-eax
 6011     51/push-ecx
 6012     52/push-edx
 6013     53/push-ebx
 6014     56/push-esi
 6015     57/push-edi
 6016     # var line/ecx: (stream byte 512)
 6017     81 5/subop/subtract %esp 0x200/imm32
 6018     68/push 0x200/imm32/size
 6019     68/push 0/imm32/read
 6020     68/push 0/imm32/write
 6021     89/<- %ecx 4/r32/esp
 6022     # var word-slice/edx: slice
 6023     68/push 0/imm32/end
 6024     68/push 0/imm32/start
 6025     89/<- %edx 4/r32/esp
 6026     # var curr-function/edi: (addr handle function)
 6027     bf/copy-to-edi _Program-functions/imm32
 6028     # var vars/ebx: (stack live-var 256)
 6029     81 5/subop/subtract %esp 0xc00/imm32
 6030     68/push 0xc00/imm32/size
 6031     68/push 0/imm32/top
 6032     89/<- %ebx 4/r32/esp
 6033     {
 6034 $parse-mu:line-loop:
 6035       (clear-stream %ecx)
 6036       (read-line-buffered *(ebp+8) %ecx)
 6037       # if (line->write == 0) break
 6038       81 7/subop/compare *ecx 0/imm32
 6039       0f 84/jump-if-= break/disp32
 6040 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
 6046       (next-mu-token %ecx %edx)
 6047       # if slice-empty?(word-slice) continue
 6048       (slice-empty? %edx)  # => eax
 6049       3d/compare-eax-and 0/imm32/false
 6050       0f 85/jump-if-!= loop/disp32
 6051       # if (*word-slice->start == "#") continue
 6052       # . eax = *word-slice->start
 6053       8b/-> *edx 0/r32/eax
 6054       8a/copy-byte *eax 0/r32/AL
 6055       81 4/subop/and %eax 0xff/imm32
 6056       # . if (eax == '#') continue
 6057       3d/compare-eax-and 0x23/imm32/hash
 6058       0f 84/jump-if-= loop/disp32
 6059       # if (slice-equal?(word-slice, "fn")) parse a function
 6060       {
 6061 $parse-mu:fn:
 6062         (slice-equal? %edx "fn")  # => eax
 6063         3d/compare-eax-and 0/imm32/false
 6064         0f 84/jump-if-= break/disp32
 6065         # var new-function/esi: (handle function)
 6066         68/push 0/imm32
 6067         68/push 0/imm32
 6068         89/<- %esi 4/r32/esp
 6069         # populate-mu-function(line, in, vars, new-function)
 6070         (allocate Heap *Function-size %esi)
 6071         # var new-function-addr/eax: (addr function)
 6072         (lookup *esi *(esi+4))  # => eax
 6073         # initialize vars
 6074         (clear-stack %ebx)
 6075         #
 6076         (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6077         (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
 6078         # *curr-function = new-function
 6079         8b/-> *esi 0/r32/eax
 6080         89/<- *edi 0/r32/eax
 6081         8b/-> *(esi+4) 0/r32/eax
 6082         89/<- *(edi+4) 0/r32/eax
 6083         # curr-function = &new-function->next
 6084         # . var tmp/eax: (addr function) = lookup(new-function)
 6085         (lookup *esi *(esi+4))  # => eax
 6086         # . curr-function = &tmp->next
 6087         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6088         # reclaim new-function
 6089         81 0/subop/add %esp 8/imm32
 6090         #
 6091         e9/jump $parse-mu:line-loop/disp32
 6092       }
 6093       # if (slice-equal?(word-slice, "sig")) parse a function signature
 6094       # Function signatures are for providing types to SubX functions.
 6095       {
 6096 $parse-mu:sig:
 6097         (slice-equal? %edx "sig")  # => eax
 6098         3d/compare-eax-and 0/imm32/false
 6099         0f 84/jump-if-= break/disp32
 6100         # edi = curr-function
 6101         57/push-edi
 6102 $bb:
 6103         8b/-> *(ebp-4) 7/r32/edi
 6104         # var new-function/esi: (handle function)
 6105         68/push 0/imm32
 6106         68/push 0/imm32
 6107         89/<- %esi 4/r32/esp
 6108         # populate-mu-function(line, in, vars, new-function)
 6109         (allocate Heap *Function-size %esi)
 6110         # var new-function-addr/eax: (addr function)
 6111         (lookup *esi *(esi+4))  # => eax
 6112         #
 6113         (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
 6114         # *curr-signature = new-function
 6115         8b/-> *esi 0/r32/eax
 6116         89/<- *edi 0/r32/eax
 6117         8b/-> *(esi+4) 0/r32/eax
 6118         89/<- *(edi+4) 0/r32/eax
 6119         # curr-signature = &new-function->next
 6120         # . var tmp/eax: (addr function) = lookup(new-function)
 6121         (lookup *esi *(esi+4))  # => eax
 6122         # . curr-function = &tmp->next
 6123         8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
 6124         # reclaim new-function
 6125         81 0/subop/add %esp 8/imm32
 6126         # save curr-function
 6127         89/<- *(ebp-4) 7/r32/edi
 6128         # restore edi
 6129         5f/pop-to-edi
 6130         #
 6131         e9/jump $parse-mu:line-loop/disp32
 6132       }
 6133       # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
 6134       {
 6135 $parse-mu:type:
 6136         (slice-equal? %edx "type")  # => eax
 6137         3d/compare-eax-and 0/imm32
 6138         0f 84/jump-if-= break/disp32
 6139         (next-mu-token %ecx %edx)
 6140         # var type-id/eax: int
 6141         (pos-or-insert-slice Type-id %edx)  # => eax
 6142         # spill
 6143         51/push-ecx
 6144         # var new-type/ecx: (handle typeinfo)
 6145         68/push 0/imm32
 6146         68/push 0/imm32
 6147         89/<- %ecx 4/r32/esp
 6148         (find-or-create-typeinfo %eax %ecx)
 6149         #
 6150         (lookup *ecx *(ecx+4))  # => eax
 6151         # TODO: ensure that 'line' has nothing else but '{'
 6152 #? (dump-typeinfos "=== aaa\n")
 6153         (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
 6154 #? (dump-typeinfos "=== zzz\n")
 6155         # reclaim new-type
 6156         81 0/subop/add %esp 8/imm32
 6157         # restore
 6158         59/pop-to-ecx
 6159         e9/jump $parse-mu:line-loop/disp32
 6160       }
 6161       # otherwise abort
 6162       e9/jump $parse-mu:error1/disp32
 6163     } # end line loop
 6164 $parse-mu:end:
 6165     # . reclaim locals
 6166     81 0/subop/add %esp 0x20c/imm32  # line
 6167     81 0/subop/add %esp 0xc08/imm32  # vars
 6168     81 0/subop/add %esp 8/imm32
 6169     # . restore registers
 6170     5f/pop-to-edi
 6171     5e/pop-to-esi
 6172     5b/pop-to-ebx
 6173     5a/pop-to-edx
 6174     59/pop-to-ecx
 6175     58/pop-to-eax
 6176     # . reclaim local
 6177     81 0/subop/add %esp 4/imm32
 6178     # . epilogue
 6179     89/<- %esp 5/r32/ebp
 6180     5d/pop-to-ebp
 6181     c3/return
 6182 
 6183 $parse-mu:error1:
 6184     # error("unexpected top-level command: " word-slice "\n")
 6185     (write-buffered *(ebp+0xc) "unexpected top-level command: ")
 6186     (write-slice-buffered *(ebp+0xc) %edx)
 6187     (write-buffered *(ebp+0xc) "\n")
 6188     (flush *(ebp+0xc))
 6189     (stop *(ebp+0x10) 1)
 6190     # never gets here
 6191 
 6192 $parse-mu:error2:
 6193     # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
 6194     (write-int32-hex-buffered *(ebp+0xc) *ebx)
 6195     (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
 6196     (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
 6197     (write-buffered *(ebp+0xc) "'\n")
 6198     (flush *(ebp+0xc))
 6199     (stop *(ebp+0x10) 1)
 6200     # never gets here
 6201 
 6202 # scenarios considered:
 6203 # ✗ fn foo  # no block
 6204 # ✓ fn foo {
 6205 # ✗ fn foo { {
 6206 # ✗ fn foo { }
 6207 # ✗ fn foo { } {
 6208 # ✗ fn foo x {
 6209 # ✗ fn foo x: {
 6210 # ✓ fn foo x: int {
 6211 # ✓ fn foo x: int {
 6212 # ✓ fn foo x: int -> y/eax: int {
 6213 # TODO:
 6214 #   disallow outputs of type `(... addr ...)`
 6215 #   disallow inputs of type `(... addr ... addr ...)`
 6216 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)
 6217     # pseudocode:
 6218     #   var word-slice: slice
 6219     #   next-mu-token(first-line, word-slice)
 6220     #   assert(word-slice not in '{' '}' '->')
 6221     #   out->name = slice-to-string(word-slice)
 6222     #   ## inouts
 6223     #   while true
 6224     #     word-slice = next-mu-token(first-line)
 6225     #     if (word-slice == '{') goto done
 6226     #     if (word-slice == '->') break
 6227     #     assert(word-slice != '}')
 6228     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6229     #     assert(v->register == null)
 6230     #     # v->block-depth is implicitly 0
 6231     #     out->inouts = append(v, out->inouts)
 6232     #     push(vars, {v, false})
 6233     #   ## outputs
 6234     #   while true
 6235     #     word-slice = next-mu-token(first-line)
 6236     #     if (word-slice == '{') break
 6237     #     assert(word-slice not in '}' '->')
 6238     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6239     #     assert(v->register != null)
 6240     #     out->outputs = append(v, out->outputs)
 6241     #   done:
 6242     #
 6243     # . prologue
 6244     55/push-ebp
 6245     89/<- %ebp 4/r32/esp
 6246     # . save registers
 6247     50/push-eax
 6248     51/push-ecx
 6249     52/push-edx
 6250     53/push-ebx
 6251     57/push-edi
 6252     # edi = out
 6253     8b/-> *(ebp+0xc) 7/r32/edi
 6254     # var word-slice/ecx: slice
 6255     68/push 0/imm32/end
 6256     68/push 0/imm32/start
 6257     89/<- %ecx 4/r32/esp
 6258     # var v/ebx: (handle var)
 6259     68/push 0/imm32
 6260     68/push 0/imm32
 6261     89/<- %ebx 4/r32/esp
 6262     # read function name
 6263     (next-mu-token *(ebp+8) %ecx)
 6264     # error checking
 6265     # if (word-slice == '{') abort
 6266     (slice-equal? %ecx "{")   # => eax
 6267     3d/compare-eax-and 0/imm32/false
 6268     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6269     # if (word-slice == '->') abort
 6270     (slice-equal? %ecx "->")   # => eax
 6271     3d/compare-eax-and 0/imm32/false
 6272     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6273     # if (word-slice == '}') abort
 6274     (slice-equal? %ecx "}")   # => eax
 6275     3d/compare-eax-and 0/imm32/false
 6276     0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6277     # save function name
 6278     (slice-to-string Heap %ecx %edi)  # Function-name
 6279     # save function inouts
 6280     {
 6281 $populate-mu-function-header:check-for-inout:
 6282       (next-mu-token *(ebp+8) %ecx)
 6283       # if (word-slice == '{') goto done
 6284       (slice-equal? %ecx "{")   # => eax
 6285       3d/compare-eax-and 0/imm32/false
 6286       0f 85/jump-if-!= $populate-mu-function-header:done/disp32
 6287       # if (word-slice == '->') break
 6288       (slice-equal? %ecx "->")   # => eax
 6289       3d/compare-eax-and 0/imm32/false
 6290       0f 85/jump-if-!= break/disp32
 6291       # if (word-slice == '}') abort
 6292       (slice-equal? %ecx "}")   # => eax
 6293       3d/compare-eax-and 0/imm32/false
 6294       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6295       # v = parse-var-with-type(word-slice, first-line)
 6296       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6297       # assert(v->register == null)
 6298       # . eax: (addr var) = lookup(v)
 6299       (lookup *ebx *(ebx+4))  # => eax
 6300       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6301       0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
 6302       # v->block-depth is implicitly 0
 6303       #
 6304       # out->inouts = append(v, out->inouts)
 6305       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6306       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6307       # push(vars, {v, false})
 6308       (push *(ebp+0x10) *ebx)
 6309       (push *(ebp+0x10) *(ebx+4))
 6310       (push *(ebp+0x10) 0)  # false
 6311       #
 6312       e9/jump loop/disp32
 6313     }
 6314     # save function outputs
 6315     {
 6316 $populate-mu-function-header:check-for-out:
 6317       (next-mu-token *(ebp+8) %ecx)
 6318       # if (word-slice == '{') break
 6319       (slice-equal? %ecx "{")   # => eax
 6320       3d/compare-eax-and 0/imm32/false
 6321       0f 85/jump-if-!= break/disp32
 6322       # if (word-slice == '->') abort
 6323       (slice-equal? %ecx "->")   # => eax
 6324       3d/compare-eax-and 0/imm32/false
 6325       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6326       # if (word-slice == '}') abort
 6327       (slice-equal? %ecx "}")   # => eax
 6328       3d/compare-eax-and 0/imm32/false
 6329       0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
 6330       # v = parse-var-with-type(word-slice, first-line)
 6331       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
 6332       # assert(var->register != null)
 6333       # . eax: (addr var) = lookup(v)
 6334       (lookup *ebx *(ebx+4))  # => eax
 6335       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6336       0f 84/jump-if-= $populate-mu-function-header:error3/disp32
 6337       # out->outputs = append(v, out->outputs)
 6338       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6339       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6340       #
 6341       e9/jump loop/disp32
 6342     }
 6343 $populate-mu-function-header:done:
 6344     (check-no-tokens-left *(ebp+8))
 6345 $populate-mu-function-header:end:
 6346     # . reclaim locals
 6347     81 0/subop/add %esp 0x10/imm32
 6348     # . restore registers
 6349     5f/pop-to-edi
 6350     5b/pop-to-ebx
 6351     5a/pop-to-edx
 6352     59/pop-to-ecx
 6353     58/pop-to-eax
 6354     # . epilogue
 6355     89/<- %esp 5/r32/ebp
 6356     5d/pop-to-ebp
 6357     c3/return
 6358 
 6359 $populate-mu-function-header:error1:
 6360     # error("function header not in form 'fn <name> {'")
 6361     (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 6362     (flush *(ebp+0x14))
 6363     (rewind-stream *(ebp+8))
 6364     (write-stream-data *(ebp+0x14) *(ebp+8))
 6365     (write-buffered *(ebp+0x14) "'\n")
 6366     (flush *(ebp+0x14))
 6367     (stop *(ebp+0x18) 1)
 6368     # never gets here
 6369 
 6370 $populate-mu-function-header:error2:
 6371     # error("fn " fn ": function inout '" var "' cannot be in a register")
 6372     (write-buffered *(ebp+0x14) "fn ")
 6373     50/push-eax
 6374     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6375     (write-buffered *(ebp+0x14) %eax)
 6376     58/pop-to-eax
 6377     (write-buffered *(ebp+0x14) ": function inout '")
 6378     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6379     (write-buffered *(ebp+0x10) %eax)
 6380     (write-buffered *(ebp+0x14) "' cannot be in a register")
 6381     (flush *(ebp+0x14))
 6382     (stop *(ebp+0x18) 1)
 6383     # never gets here
 6384 
 6385 $populate-mu-function-header:error3:
 6386     # error("fn " fn ": function output '" var "' must be in a register")
 6387     (write-buffered *(ebp+0x14) "fn ")
 6388     50/push-eax
 6389     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6390     (write-buffered *(ebp+0x14) %eax)
 6391     58/pop-to-eax
 6392     (write-buffered *(ebp+0x14) ": function output '")
 6393     (lookup *ebx *(ebx+4))  # => eax
 6394     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6395     (write-buffered *(ebp+0x14) %eax)
 6396     (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
 6397     (rewind-stream *(ebp+8))
 6398     (write-stream-data *(ebp+0x14) *(ebp+8))
 6399     (write-buffered *(ebp+0x14) "'\n")
 6400     (flush *(ebp+0x14))
 6401     (stop *(ebp+0x18) 1)
 6402     # never gets here
 6403 
 6404 # scenarios considered:
 6405 # ✓ fn foo
 6406 # ✗ fn foo {
 6407 # ✓ fn foo x
 6408 # ✓ fn foo x: int
 6409 # ✓ fn foo x: int -> y/eax: int
 6410 # TODO:
 6411 #   disallow outputs of type `(... addr ...)`
 6412 #   disallow inputs of type `(... addr ... addr ...)`
 6413 populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 6414     # pseudocode:
 6415     #   var word-slice: slice
 6416     #   next-mu-token(first-line, word-slice)
 6417     #   assert(word-slice not in '{' '}' '->')
 6418     #   out->name = slice-to-string(word-slice)
 6419     #   ## inouts
 6420     #   while true
 6421     #     word-slice = next-mu-token(first-line)
 6422     #     if slice-empty?(word-slice) break
 6423     #     if (word-slice == '->') break
 6424     #     assert(word-slice not in '{' '}')
 6425     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6426     #     assert(v->register == null)
 6427     #     # v->block-depth is implicitly 0
 6428     #     out->inouts = append(v, out->inouts)
 6429     #   ## outputs
 6430     #   while true
 6431     #     word-slice = next-mu-token(first-line)
 6432     #     if slice-empty?(word-slice) break
 6433     #     assert(word-slice not in '{' '}' '->')
 6434     #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
 6435     #     assert(v->register != null)
 6436     #     out->outputs = append(v, out->outputs)
 6437     #
 6438     # . prologue
 6439     55/push-ebp
 6440     89/<- %ebp 4/r32/esp
 6441     # . save registers
 6442     50/push-eax
 6443     51/push-ecx
 6444     52/push-edx
 6445     53/push-ebx
 6446     57/push-edi
 6447     # edi = out
 6448     8b/-> *(ebp+0xc) 7/r32/edi
 6449     # var word-slice/ecx: slice
 6450     68/push 0/imm32/end
 6451     68/push 0/imm32/start
 6452     89/<- %ecx 4/r32/esp
 6453     # var v/ebx: (handle var)
 6454     68/push 0/imm32
 6455     68/push 0/imm32
 6456     89/<- %ebx 4/r32/esp
 6457     # read function name
 6458     (next-mu-token *(ebp+8) %ecx)
 6459     # error checking
 6460     # if (word-slice == '{') abort
 6461     (slice-equal? %ecx "{")   # => eax
 6462     3d/compare-eax-and 0/imm32/false
 6463     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6464     # if (word-slice == '->') abort
 6465     (slice-equal? %ecx "->")   # => eax
 6466     3d/compare-eax-and 0/imm32/false
 6467     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6468     # if (word-slice == '}') abort
 6469     (slice-equal? %ecx "}")   # => eax
 6470     3d/compare-eax-and 0/imm32/false
 6471     0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6472     # save function name
 6473     (slice-to-string Heap %ecx %edi)  # Function-name
 6474     # save function inouts
 6475     {
 6476 $populate-mu-function-signature:check-for-inout:
 6477       (next-mu-token *(ebp+8) %ecx)
 6478       (slice-empty? %ecx)  # => eax
 6479       3d/compare-eax-and 0/imm32/false
 6480       0f 85/jump-if-!= break/disp32
 6481       # if (word-slice == '->') break
 6482       (slice-equal? %ecx "->")   # => eax
 6483       3d/compare-eax-and 0/imm32/false
 6484       0f 85/jump-if-!= break/disp32
 6485       # if (word-slice == '{') abort
 6486       (slice-equal? %ecx "{")   # => eax
 6487       3d/compare-eax-and 0/imm32/false
 6488       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6489       # if (word-slice == '}') abort
 6490       (slice-equal? %ecx "}")   # => eax
 6491       3d/compare-eax-and 0/imm32/false
 6492       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6493       # v = parse-var-with-type(word-slice, first-line)
 6494       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 6495       # assert(v->register == null)
 6496       # . eax: (addr var) = lookup(v)
 6497       (lookup *ebx *(ebx+4))  # => eax
 6498       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6499       0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
 6500       # v->block-depth is implicitly 0
 6501       #
 6502       # out->inouts = append(v, out->inouts)
 6503       8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
 6504       (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
 6505       #
 6506       e9/jump loop/disp32
 6507     }
 6508     # save function outputs
 6509     {
 6510 $populate-mu-function-signature:check-for-out:
 6511       (next-mu-token *(ebp+8) %ecx)
 6512       (slice-empty? %ecx)  # => eax
 6513       3d/compare-eax-and 0/imm32/false
 6514       0f 85/jump-if-!= break/disp32
 6515       # if (word-slice == '{') abort
 6516       (slice-equal? %ecx "{")   # => eax
 6517       3d/compare-eax-and 0/imm32/false
 6518       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6519       # if (word-slice == '->') abort
 6520       (slice-equal? %ecx "->")   # => eax
 6521       3d/compare-eax-and 0/imm32/false
 6522       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6523       # if (word-slice == '}') abort
 6524       (slice-equal? %ecx "}")   # => eax
 6525       3d/compare-eax-and 0/imm32/false
 6526       0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
 6527       # v = parse-var-with-type(word-slice, first-line)
 6528       (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
 6529       # assert(var->register != null)
 6530       # . eax: (addr var) = lookup(v)
 6531       (lookup *ebx *(ebx+4))  # => eax
 6532       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
 6533       0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
 6534       # out->outputs = append(v, out->outputs)
 6535       8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
 6536       (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
 6537       #
 6538       e9/jump loop/disp32
 6539     }
 6540 $populate-mu-function-signature:done:
 6541     (check-no-tokens-left *(ebp+8))
 6542 $populate-mu-function-signature:end:
 6543     # . reclaim locals
 6544     81 0/subop/add %esp 0x10/imm32
 6545     # . restore registers
 6546     5f/pop-to-edi
 6547     5b/pop-to-ebx
 6548     5a/pop-to-edx
 6549     59/pop-to-ecx
 6550     58/pop-to-eax
 6551     # . epilogue
 6552     89/<- %esp 5/r32/ebp
 6553     5d/pop-to-ebp
 6554     c3/return
 6555 
 6556 $populate-mu-function-signature:error1:
 6557     # error("function signature not in form 'fn <name> {'")
 6558     (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
 6559     (flush *(ebp+0x10))
 6560     (rewind-stream *(ebp+8))
 6561     (write-stream-data *(ebp+0x10) *(ebp+8))
 6562     (write-buffered *(ebp+0x10) "'\n")
 6563     (flush *(ebp+0x10))
 6564     (stop *(ebp+0x14) 1)
 6565     # never gets here
 6566 
 6567 $populate-mu-function-signature:error2:
 6568     # error("fn " fn ": function inout '" var "' cannot be in a register")
 6569     (write-buffered *(ebp+0x10) "fn ")
 6570     50/push-eax
 6571     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6572     (write-buffered *(ebp+0x10) %eax)
 6573     58/pop-to-eax
 6574     (write-buffered *(ebp+0x10) ": function inout '")
 6575     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6576     (write-buffered *(ebp+0x10) %eax)
 6577     (write-buffered *(ebp+0x10) "' cannot be in a register")
 6578     (flush *(ebp+0x10))
 6579     (stop *(ebp+0x14) 1)
 6580     # never gets here
 6581 
 6582 $populate-mu-function-signature:error3:
 6583     # error("fn " fn ": function output '" var "' must be in a register")
 6584     (write-buffered *(ebp+0x10) "fn ")
 6585     50/push-eax
 6586     (lookup *edi *(edi+4))  # Function-name Function-name => eax
 6587     (write-buffered *(ebp+0x10) %eax)
 6588     58/pop-to-eax
 6589     (write-buffered *(ebp+0x10) ": function output '")
 6590     (lookup *ebx *(ebx+4))  # => eax
 6591     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 6592     (write-buffered *(ebp+0x10) %eax)
 6593     (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
 6594     (rewind-stream *(ebp+8))
 6595     (write-stream-data *(ebp+0x10) *(ebp+8))
 6596     (write-buffered *(ebp+0x10) "'\n")
 6597     (flush *(ebp+0x10))
 6598     (stop *(ebp+0x14) 1)
 6599     # never gets here
 6600 
 6601 test-function-header-with-arg:
 6602     # . prologue
 6603     55/push-ebp
 6604     89/<- %ebp 4/r32/esp
 6605     # setup
 6606     (clear-stream _test-input-stream)
 6607     (write _test-input-stream "foo n: int {\n")
 6608     # var result/ecx: function
 6609     2b/subtract *Function-size 4/r32/esp
 6610     89/<- %ecx 4/r32/esp
 6611     (zero-out %ecx *Function-size)
 6612     # var vars/ebx: (stack live-var 16)
 6613     81 5/subop/subtract %esp 0xc0/imm32
 6614     68/push 0xc0/imm32/size
 6615     68/push 0/imm32/top
 6616     89/<- %ebx 4/r32/esp
 6617     # convert
 6618     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6619     # check result->name
 6620     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6621     (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
 6622     # var v/edx: (addr var) = result->inouts->value
 6623     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6624     (lookup *eax *(eax+4))  # List-value List-value => eax
 6625     89/<- %edx 0/r32/eax
 6626     # check v->name
 6627     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 6628     (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
 6629     # check v->type
 6630     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 6631     (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
 6632     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
 6633     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
 6634     # . epilogue
 6635     89/<- %esp 5/r32/ebp
 6636     5d/pop-to-ebp
 6637     c3/return
 6638 
 6639 test-function-header-with-multiple-args:
 6640     # . prologue
 6641     55/push-ebp
 6642     89/<- %ebp 4/r32/esp
 6643     # setup
 6644     (clear-stream _test-input-stream)
 6645     (write _test-input-stream "foo a: int, b: int c: int {\n")
 6646     # result/ecx: function
 6647     2b/subtract *Function-size 4/r32/esp
 6648     89/<- %ecx 4/r32/esp
 6649     (zero-out %ecx *Function-size)
 6650     # var vars/ebx: (stack live-var 16)
 6651     81 5/subop/subtract %esp 0xc0/imm32
 6652     68/push 0xc0/imm32/size
 6653     68/push 0/imm32/top
 6654     89/<- %ebx 4/r32/esp
 6655     # convert
 6656     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6657     # check result->name
 6658     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6659     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
 6660     # var inouts/edx: (addr list var) = lookup(result->inouts)
 6661     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6662     89/<- %edx 0/r32/eax
 6663 $test-function-header-with-multiple-args:inout0:
 6664     # var v/ebx: (addr var) = lookup(inouts->value)
 6665     (lookup *edx *(edx+4))  # List-value List-value => eax
 6666     89/<- %ebx 0/r32/eax
 6667     # check v->name
 6668     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6669     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
 6670     # check v->type
 6671     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6672     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
 6673     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
 6674     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
 6675 $test-function-header-with-multiple-args:inout1:
 6676     # inouts = lookup(inouts->next)
 6677     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6678     89/<- %edx 0/r32/eax
 6679     # v = lookup(inouts->value)
 6680     (lookup *edx *(edx+4))  # List-value List-value => eax
 6681     89/<- %ebx 0/r32/eax
 6682     # check v->name
 6683     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6684     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
 6685     # check v->type
 6686     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6687     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
 6688     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
 6689     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
 6690 $test-function-header-with-multiple-args:inout2:
 6691     # inouts = lookup(inouts->next)
 6692     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6693     89/<- %edx 0/r32/eax
 6694     # v = lookup(inouts->value)
 6695     (lookup *edx *(edx+4))  # List-value List-value => eax
 6696     89/<- %ebx 0/r32/eax
 6697     # check v->name
 6698     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6699     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
 6700     # check v->type
 6701     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6702     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
 6703     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
 6704     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
 6705     # . epilogue
 6706     89/<- %esp 5/r32/ebp
 6707     5d/pop-to-ebp
 6708     c3/return
 6709 
 6710 test-function-header-with-multiple-args-and-outputs:
 6711     # . prologue
 6712     55/push-ebp
 6713     89/<- %ebp 4/r32/esp
 6714     # setup
 6715     (clear-stream _test-input-stream)
 6716     (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
 6717     # result/ecx: function
 6718     2b/subtract *Function-size 4/r32/esp
 6719     89/<- %ecx 4/r32/esp
 6720     (zero-out %ecx *Function-size)
 6721     # var vars/ebx: (stack live-var 16)
 6722     81 5/subop/subtract %esp 0xc0/imm32
 6723     68/push 0xc0/imm32/size
 6724     68/push 0/imm32/top
 6725     89/<- %ebx 4/r32/esp
 6726     # convert
 6727     (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
 6728     # check result->name
 6729     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
 6730     (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
 6731     # var inouts/edx: (addr list var) = lookup(result->inouts)
 6732     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
 6733     89/<- %edx 0/r32/eax
 6734 $test-function-header-with-multiple-args-and-outputs:inout0:
 6735     # var v/ebx: (addr var) = lookup(inouts->value)
 6736     (lookup *edx *(edx+4))  # List-value List-value => eax
 6737     89/<- %ebx 0/r32/eax
 6738     # check v->name
 6739     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6740     (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
 6741     # check v->type
 6742     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6743     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
 6744     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
 6745     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
 6746 $test-function-header-with-multiple-args-and-outputs:inout1:
 6747     # inouts = lookup(inouts->next)
 6748     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6749     89/<- %edx 0/r32/eax
 6750     # v = lookup(inouts->value)
 6751     (lookup *edx *(edx+4))  # List-value List-value => eax
 6752     89/<- %ebx 0/r32/eax
 6753     # check v->name
 6754     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6755     (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
 6756     # check v->type
 6757     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6758     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
 6759     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
 6760     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
 6761 $test-function-header-with-multiple-args-and-outputs:inout2:
 6762     # inouts = lookup(inouts->next)
 6763     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6764     89/<- %edx 0/r32/eax
 6765     # v = lookup(inouts->value)
 6766     (lookup *edx *(edx+4))  # List-value List-value => eax
 6767     89/<- %ebx 0/r32/eax
 6768     # check v->name
 6769     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6770     (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
 6771     # check v->type
 6772     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6773     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
 6774     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
 6775     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
 6776 $test-function-header-with-multiple-args-and-outputs:out0:
 6777     # var outputs/edx: (addr list var) = lookup(result->outputs)
 6778     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 6779     89/<- %edx 0/r32/eax
 6780     # v = lookup(outputs->value)
 6781     (lookup *edx *(edx+4))  # List-value List-value => eax
 6782     89/<- %ebx 0/r32/eax
 6783     # check v->name
 6784     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6785     (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
 6786     # check v->register
 6787     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 6788     (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
 6789     # check v->type
 6790     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6791     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
 6792     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
 6793     (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
 6794 $test-function-header-with-multiple-args-and-outputs:out1:
 6795     # outputs = lookup(outputs->next)
 6796     (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
 6797     89/<- %edx 0/r32/eax
 6798     # v = lookup(inouts->value)
 6799     (lookup *edx *(edx+4))  # List-value List-value => eax
 6800     89/<- %ebx 0/r32/eax
 6801     # check v->name
 6802     (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
 6803     (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
 6804     # check v->register
 6805     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
 6806     (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
 6807     # check v->type
 6808     (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
 6809     (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
 6810     (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
 6811     (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
 6812     # . epilogue
 6813     89/<- %esp 5/r32/ebp
 6814     5d/pop-to-ebp
 6815     c3/return
 6816 
 6817 # format for variables with types
 6818 #   x: int
 6819 #   x: int,
 6820 #   x/eax: int
 6821 #   x/eax: int,
 6822 # ignores at most one trailing comma
 6823 # WARNING: modifies name
 6824 parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 6825     # pseudocode:
 6826     #   var s: slice
 6827     #   if (!slice-ends-with(name, ":"))
 6828     #     abort
 6829     #   --name->end to skip ':'
 6830     #   next-token-from-slice(name->start, name->end, '/', s)
 6831     #   new-var-from-slice(s, out)
 6832     #   ## register
 6833     #   next-token-from-slice(s->end, name->end, '/', s)
 6834     #   if (!slice-empty?(s))
 6835     #     out->register = slice-to-string(s)
 6836     #   ## type
 6837     #   var type: (handle type-tree) = parse-type(first-line)
 6838     #   out->type = type
 6839     #
 6840     # . prologue
 6841     55/push-ebp
 6842     89/<- %ebp 4/r32/esp
 6843     # . save registers
 6844     50/push-eax
 6845     51/push-ecx
 6846     52/push-edx
 6847     53/push-ebx
 6848     56/push-esi
 6849     57/push-edi
 6850     # esi = name
 6851     8b/-> *(ebp+8) 6/r32/esi
 6852     # if (!slice-ends-with?(name, ":")) abort
 6853     8b/-> *(esi+4) 1/r32/ecx  # Slice-end
 6854     49/decrement-ecx
 6855     8a/copy-byte *ecx 1/r32/CL
 6856     81 4/subop/and %ecx 0xff/imm32
 6857     81 7/subop/compare %ecx 0x3a/imm32/colon
 6858     0f 85/jump-if-!= $parse-var-with-type:abort/disp32
 6859     # --name->end to skip ':'
 6860     ff 1/subop/decrement *(esi+4)
 6861     # var s/ecx: slice
 6862     68/push 0/imm32/end
 6863     68/push 0/imm32/start
 6864     89/<- %ecx 4/r32/esp
 6865 $parse-var-with-type:parse-name:
 6866     (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
 6867 $parse-var-with-type:create-var:
 6868     # new-var-from-slice(s, out)
 6869     (new-var-from-slice Heap %ecx *(ebp+0x10))
 6870     # save out->register
 6871 $parse-var-with-type:save-register:
 6872     # . var out-addr/edi: (addr var) = lookup(*out)
 6873     8b/-> *(ebp+0x10) 7/r32/edi
 6874     (lookup *edi *(edi+4))  # => eax
 6875     89/<- %edi 0/r32/eax
 6876     # . s = next-token(...)
 6877     (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
 6878     # . if (!slice-empty?(s)) out->register = slice-to-string(s)
 6879     {
 6880 $parse-var-with-type:write-register:
 6881       (slice-empty? %ecx)  # => eax
 6882       3d/compare-eax-and 0/imm32/false
 6883       75/jump-if-!= break/disp8
 6884       # out->register = slice-to-string(s)
 6885       8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
 6886       (slice-to-string Heap %ecx %eax)
 6887     }
 6888 $parse-var-with-type:save-type:
 6889     8d/copy-address *(edi+8) 0/r32/eax  # Var-type
 6890     (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 6891 $parse-var-with-type:end:
 6892     # . reclaim locals
 6893     81 0/subop/add %esp 8/imm32
 6894     # . restore registers
 6895     5f/pop-to-edi
 6896     5e/pop-to-esi
 6897     5b/pop-to-ebx
 6898     5a/pop-to-edx
 6899     59/pop-to-ecx
 6900     58/pop-to-eax
 6901     # . epilogue
 6902     89/<- %esp 5/r32/ebp
 6903     5d/pop-to-ebp
 6904     c3/return
 6905 
 6906 $parse-var-with-type:abort:
 6907     # error("var should have form 'name: type' in '" line "'\n")
 6908     (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
 6909     (flush *(ebp+0x14))
 6910     (rewind-stream *(ebp+0xc))
 6911     (write-stream-data *(ebp+0x14) *(ebp+0xc))
 6912     (write-buffered *(ebp+0x14) "'\n")
 6913     (flush *(ebp+0x14))
 6914     (stop *(ebp+0x18) 1)
 6915     # never gets here
 6916 
 6917 parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 6918     # pseudocode:
 6919     #   var s: slice = next-mu-token(in)
 6920     #   assert s != ""
 6921     #   assert s != "->"
 6922     #   assert s != "{"
 6923     #   assert s != "}"
 6924     #   if s == ")"
 6925     #     return
 6926     #   out = allocate(Type-tree)
 6927     #   if s != "("
 6928     #     HACK: if s is an int, parse and return it
 6929     #     out->left-is-atom? = true
 6930     #     out->value = pos-or-insert-slice(Type-id, s)
 6931     #     return
 6932     #   out->left = parse-type(ad, in)
 6933     #   out->right = parse-type-tree(ad, in)
 6934     #
 6935     # . prologue
 6936     55/push-ebp
 6937     89/<- %ebp 4/r32/esp
 6938     # . save registers
 6939     50/push-eax
 6940     51/push-ecx
 6941     52/push-edx
 6942     # clear out
 6943     (zero-out *(ebp+0x10) *Handle-size)
 6944     # var s/ecx: slice
 6945     68/push 0/imm32
 6946     68/push 0/imm32
 6947     89/<- %ecx 4/r32/esp
 6948     # s = next-mu-token(in)
 6949     (next-mu-token *(ebp+0xc) %ecx)
 6950 #?     (write-buffered Stderr "tok: ")
 6951 #?     (write-slice-buffered Stderr %ecx)
 6952 #?     (write-buffered Stderr "$\n")
 6953 #?     (flush Stderr)
 6954     # assert s != ""
 6955     (slice-equal? %ecx "")  # => eax
 6956     3d/compare-eax-and 0/imm32/false
 6957     0f 85/jump-if-!= $parse-type:abort/disp32
 6958     # assert s != "{"
 6959     (slice-equal? %ecx "{")  # => eax
 6960     3d/compare-eax-and 0/imm32/false
 6961     0f 85/jump-if-!= $parse-type:abort/disp32
 6962     # assert s != "}"
 6963     (slice-equal? %ecx "}")  # => eax
 6964     3d/compare-eax-and 0/imm32/false
 6965     0f 85/jump-if-!= $parse-type:abort/disp32
 6966     # assert s != "->"
 6967     (slice-equal? %ecx "->")  # => eax
 6968     3d/compare-eax-and 0/imm32/false
 6969     0f 85/jump-if-!= $parse-type:abort/disp32
 6970     # if (s == ")") return
 6971     (slice-equal? %ecx ")")  # => eax
 6972     3d/compare-eax-and 0/imm32/false
 6973     0f 85/jump-if-!= $parse-type:end/disp32
 6974     # out = new tree
 6975     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 6976     # var out-addr/edx: (addr type-tree) = lookup(*out)
 6977     8b/-> *(ebp+0x10) 2/r32/edx
 6978     (lookup *edx *(edx+4))  # => eax
 6979     89/<- %edx 0/r32/eax
 6980     {
 6981       # if (s != "(") break
 6982       (slice-equal? %ecx "(")  # => eax
 6983       3d/compare-eax-and 0/imm32/false
 6984       75/jump-if-!= break/disp8
 6985       # if s is a number, store it in the type's size field
 6986       {
 6987 $parse-type:check-for-int:
 6988         (is-hex-int? %ecx)  # => eax
 6989         3d/compare-eax-and 0/imm32/false
 6990         74/jump-if-= break/disp8
 6991 $parse-type:int:
 6992         (parse-hex-int-from-slice %ecx)  # => eax
 6993         c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
 6994         89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
 6995         e9/jump $parse-type:end/disp32
 6996       }
 6997 $parse-type:atom:
 6998       # out->left-is-atom? = true
 6999       c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
 7000       # out->value = pos-or-insert-slice(Type-id, s)
 7001       (pos-or-insert-slice Type-id %ecx)  # => eax
 7002       89/<- *(edx+4) 0/r32/eax  # Type-tree-value
 7003       e9/jump $parse-type:end/disp32
 7004     }
 7005 $parse-type:non-atom:
 7006     # otherwise s == "("
 7007     # out->left = parse-type(ad, in)
 7008     8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
 7009     (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7010     # out->right = parse-type-tree(ad, in)
 7011     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7012     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7013 $parse-type:end:
 7014     # . reclaim locals
 7015     81 0/subop/add %esp 8/imm32
 7016     # . restore registers
 7017     5a/pop-to-edx
 7018     59/pop-to-ecx
 7019     58/pop-to-eax
 7020     # . epilogue
 7021     89/<- %esp 5/r32/ebp
 7022     5d/pop-to-ebp
 7023     c3/return
 7024 
 7025 $parse-type:abort:
 7026     # error("unexpected token when parsing type: '" s "'\n")
 7027     (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
 7028     (write-slice-buffered *(ebp+0x14) %ecx)
 7029     (write-buffered *(ebp+0x14) "'\n")
 7030     (flush *(ebp+0x14))
 7031     (stop *(ebp+0x18) 1)
 7032     # never gets here
 7033 
 7034 parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
 7035     # pseudocode:
 7036     #   var tmp: (handle type-tree) = parse-type(ad, in)
 7037     #   if tmp == 0
 7038     #     return 0
 7039     #   out = allocate(Type-tree)
 7040     #   out->left = tmp
 7041     #   out->right = parse-type-tree(ad, in)
 7042     #
 7043     # . prologue
 7044     55/push-ebp
 7045     89/<- %ebp 4/r32/esp
 7046     # . save registers
 7047     50/push-eax
 7048     51/push-ecx
 7049     52/push-edx
 7050     #
 7051     (zero-out *(ebp+0x10) *Handle-size)
 7052     # var tmp/ecx: (handle type-tree)
 7053     68/push 0/imm32
 7054     68/push 0/imm32
 7055     89/<- %ecx 4/r32/esp
 7056     # tmp = parse-type(ad, in)
 7057     (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
 7058     # if (tmp == 0) return
 7059     81 7/subop/compare *ecx 0/imm32
 7060     74/jump-if-= $parse-type-tree:end/disp8
 7061     # out = new tree
 7062     (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
 7063     # var out-addr/edx: (addr tree) = lookup(*out)
 7064     8b/-> *(ebp+0x10) 2/r32/edx
 7065     (lookup *edx *(edx+4))  # => eax
 7066     89/<- %edx 0/r32/eax
 7067     # out->left = tmp
 7068     8b/-> *ecx 0/r32/eax
 7069     89/<- *(edx+4) 0/r32/eax  # Type-tree-left
 7070     8b/-> *(ecx+4) 0/r32/eax
 7071     89/<- *(edx+8) 0/r32/eax  # Type-tree-left
 7072     # out->right = parse-type-tree(ad, in)
 7073     8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
 7074     (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
 7075 $parse-type-tree:end:
 7076     # . reclaim locals
 7077     81 0/subop/add %esp 8/imm32
 7078     # . restore registers
 7079     5a/pop-to-edx
 7080     59/pop-to-ecx
 7081     58/pop-to-eax
 7082     # . epilogue
 7083     89/<- %esp 5/r32/ebp
 7084     5d/pop-to-ebp
 7085     c3/return
 7086 
 7087 next-mu-token:  # in: (addr stream byte), out: (addr slice)
 7088     # pseudocode:
 7089     # start:
 7090     #   skip-chars-matching-whitespace(in)
 7091     #   if in->read >= in->write              # end of in
 7092     #     out = {0, 0}
 7093     #     return
 7094     #   out->start = &in->data[in->read]
 7095     #   var curr-byte/eax: byte = in->data[in->read]
 7096     #   if curr->byte == ','                  # comment token
 7097     #     ++in->read
 7098     #     goto start
 7099     #   if curr-byte == '#'                   # comment
 7100     #     goto done                             # treat as eof
 7101     #   if curr-byte == '"'                   # string literal
 7102     #     skip-string(in)
 7103     #     goto done                           # no metadata
 7104     #   if curr-byte == '('
 7105     #     ++in->read
 7106     #     goto done
 7107     #   if curr-byte == ')'
 7108     #     ++in->read
 7109     #     goto done
 7110     #   # read a word
 7111     #   while true
 7112     #     if in->read >= in->write
 7113     #       break
 7114     #     curr-byte = in->data[in->read]
 7115     #     if curr-byte == ' '
 7116     #       break
 7117     #     if curr-byte == '\r'
 7118     #       break
 7119     #     if curr-byte == '\n'
 7120     #       break
 7121     #     if curr-byte == '('
 7122     #       break
 7123     #     if curr-byte == ')'
 7124     #       break
 7125     #     if curr-byte == ','
 7126     #       break
 7127     #     ++in->read
 7128     # done:
 7129     #   out->end = &in->data[in->read]
 7130     #
 7131     # . prologue
 7132     55/push-ebp
 7133     89/<- %ebp 4/r32/esp
 7134     # . save registers
 7135     50/push-eax
 7136     51/push-ecx
 7137     56/push-esi
 7138     57/push-edi
 7139     # esi = in
 7140     8b/-> *(ebp+8) 6/r32/esi
 7141     # edi = out
 7142     8b/-> *(ebp+0xc) 7/r32/edi
 7143 $next-mu-token:start:
 7144     (skip-chars-matching-whitespace %esi)
 7145 $next-mu-token:check0:
 7146     # if (in->read >= in->write) return out = {0, 0}
 7147     # . ecx = in->read
 7148     8b/-> *(esi+4) 1/r32/ecx
 7149     # . if (ecx >= in->write) return out = {0, 0}
 7150     3b/compare<- *esi 1/r32/ecx
 7151     c7 0/subop/copy *edi 0/imm32
 7152     c7 0/subop/copy *(edi+4) 0/imm32
 7153     0f 8d/jump-if->= $next-mu-token:end/disp32
 7154     # out->start = &in->data[in->read]
 7155     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7156     89/<- *edi 0/r32/eax
 7157     # var curr-byte/eax: byte = in->data[in->read]
 7158     31/xor-with %eax 0/r32/eax
 7159     8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7160     {
 7161 $next-mu-token:check-for-comma:
 7162       # if (curr-byte != ',') break
 7163       3d/compare-eax-and 0x2c/imm32/comma
 7164       75/jump-if-!= break/disp8
 7165       # ++in->read
 7166       ff 0/subop/increment *(esi+4)
 7167       # restart
 7168       e9/jump $next-mu-token:start/disp32
 7169     }
 7170     {
 7171 $next-mu-token:check-for-comment:
 7172       # if (curr-byte != '#') break
 7173       3d/compare-eax-and 0x23/imm32/pound
 7174       75/jump-if-!= break/disp8
 7175       # return eof
 7176       e9/jump $next-mu-token:done/disp32
 7177     }
 7178     {
 7179 $next-mu-token:check-for-string-literal:
 7180       # if (curr-byte != '"') break
 7181       3d/compare-eax-and 0x22/imm32/dquote
 7182       75/jump-if-!= break/disp8
 7183       (skip-string %esi)
 7184       # return
 7185       e9/jump $next-mu-token:done/disp32
 7186     }
 7187     {
 7188 $next-mu-token:check-for-open-paren:
 7189       # if (curr-byte != '(') break
 7190       3d/compare-eax-and 0x28/imm32/open-paren
 7191       75/jump-if-!= break/disp8
 7192       # ++in->read
 7193       ff 0/subop/increment *(esi+4)
 7194       # return
 7195       e9/jump $next-mu-token:done/disp32
 7196     }
 7197     {
 7198 $next-mu-token:check-for-close-paren:
 7199       # if (curr-byte != ')') break
 7200       3d/compare-eax-and 0x29/imm32/close-paren
 7201       75/jump-if-!= break/disp8
 7202       # ++in->read
 7203       ff 0/subop/increment *(esi+4)
 7204       # return
 7205       e9/jump $next-mu-token:done/disp32
 7206     }
 7207     {
 7208 $next-mu-token:regular-word-without-metadata:
 7209       # if (in->read >= in->write) break
 7210       # . ecx = in->read
 7211       8b/-> *(esi+4) 1/r32/ecx
 7212       # . if (ecx >= in->write) break
 7213       3b/compare<- *esi 1/r32/ecx
 7214       7d/jump-if->= break/disp8
 7215       # var c/eax: byte = in->data[in->read]
 7216       31/xor-with %eax 0/r32/eax
 7217       8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
 7218       # if (c == ' ') break
 7219       3d/compare-eax-and 0x20/imm32/space
 7220       74/jump-if-= break/disp8
 7221       # if (c == '\r') break
 7222       3d/compare-eax-and 0xd/imm32/carriage-return
 7223       74/jump-if-= break/disp8
 7224       # if (c == '\n') break
 7225       3d/compare-eax-and 0xa/imm32/newline
 7226       74/jump-if-= break/disp8
 7227       # if (c == '(') break
 7228       3d/compare-eax-and 0x28/imm32/open-paren
 7229       0f 84/jump-if-= break/disp32
 7230       # if (c == ')') break
 7231       3d/compare-eax-and 0x29/imm32/close-paren
 7232       0f 84/jump-if-= break/disp32
 7233       # if (c == ',') break
 7234       3d/compare-eax-and 0x2c/imm32/comma
 7235       0f 84/jump-if-= break/disp32
 7236       # ++in->read
 7237       ff 0/subop/increment *(esi+4)
 7238       #
 7239       e9/jump loop/disp32
 7240     }
 7241 $next-mu-token:done:
 7242     # out->end = &in->data[in->read]
 7243     8b/-> *(esi+4) 1/r32/ecx
 7244     8d/copy-address *(esi+ecx+0xc) 0/r32/eax
 7245     89/<- *(edi+4) 0/r32/eax
 7246 $next-mu-token:end:
 7247     # . restore registers
 7248     5f/pop-to-edi
 7249     5e/pop-to-esi
 7250     59/pop-to-ecx
 7251     58/pop-to-eax
 7252     # . epilogue
 7253     89/<- %esp 5/r32/ebp
 7254     5d/pop-to-ebp
 7255     c3/return
 7256 
 7257 pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7258     # . prologue
 7259     55/push-ebp
 7260     89/<- %ebp 4/r32/esp
 7261     # if (pos-slice(arr, s) != -1) return it
 7262     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7263     3d/compare-eax-and -1/imm32
 7264     75/jump-if-!= $pos-or-insert-slice:end/disp8
 7265 $pos-or-insert-slice:insert:
 7266     # var s2/eax: (handle array byte)
 7267     68/push 0/imm32
 7268     68/push 0/imm32
 7269     89/<- %eax 4/r32/esp
 7270     (slice-to-string Heap *(ebp+0xc) %eax)
 7271     # throw away alloc-id
 7272     (lookup *eax *(eax+4))  # => eax
 7273     (write-int *(ebp+8) %eax)
 7274     (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
 7275 $pos-or-insert-slice:end:
 7276     # . reclaim locals
 7277     81 0/subop/add %esp 8/imm32
 7278     # . epilogue
 7279     89/<- %esp 5/r32/ebp
 7280     5d/pop-to-ebp
 7281     c3/return
 7282 
 7283 # return the index in an array of strings matching 's', -1 if not found
 7284 # index is denominated in elements, not bytes
 7285 pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
 7286     # . prologue
 7287     55/push-ebp
 7288     89/<- %ebp 4/r32/esp
 7289     # . save registers
 7290     51/push-ecx
 7291     52/push-edx
 7292     53/push-ebx
 7293     56/push-esi
 7294 #?     (write-buffered Stderr "pos-slice: ")
 7295 #?     (write-slice-buffered Stderr *(ebp+0xc))
 7296 #?     (write-buffered Stderr "\n")
 7297 #?     (flush Stderr)
 7298     # esi = arr
 7299     8b/-> *(ebp+8) 6/r32/esi
 7300     # var index/ecx: int = 0
 7301     b9/copy-to-ecx 0/imm32
 7302     # var curr/edx: (addr (addr array byte)) = arr->data
 7303     8d/copy-address *(esi+0xc) 2/r32/edx
 7304     # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
 7305     8b/-> *esi 3/r32/ebx
 7306     8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
 7307     {
 7308 #?       (write-buffered Stderr "  ")
 7309 #?       (write-int32-hex-buffered Stderr %ecx)
 7310 #?       (write-buffered Stderr "\n")
 7311 #?       (flush Stderr)
 7312       # if (curr >= max) return -1
 7313       39/compare %edx 3/r32/ebx
 7314       b8/copy-to-eax -1/imm32
 7315       73/jump-if-addr>= $pos-slice:end/disp8
 7316       # if (slice-equal?(s, *curr)) break
 7317       (slice-equal? *(ebp+0xc) *edx)  # => eax
 7318       3d/compare-eax-and 0/imm32/false
 7319       75/jump-if-!= break/disp8
 7320       # ++index
 7321       41/increment-ecx
 7322       # curr += 4
 7323       81 0/subop/add %edx 4/imm32
 7324       #
 7325       eb/jump loop/disp8
 7326     }
 7327     # return index
 7328     89/<- %eax 1/r32/ecx
 7329 $pos-slice:end:
 7330 #?     (write-buffered Stderr "=> ")
 7331 #?     (write-int32-hex-buffered Stderr %eax)
 7332 #?     (write-buffered Stderr "\n")
 7333     # . restore registers
 7334     5e/pop-to-esi
 7335     5b/pop-to-ebx
 7336     5a/pop-to-edx
 7337     59/pop-to-ecx
 7338     # . epilogue
 7339     89/<- %esp 5/r32/ebp
 7340     5d/pop-to-ebp
 7341     c3/return
 7342 
 7343 test-parse-var-with-type:
 7344     # . prologue
 7345     55/push-ebp
 7346     89/<- %ebp 4/r32/esp
 7347     # (eax..ecx) = "x:"
 7348     b8/copy-to-eax "x:"/imm32
 7349     8b/-> *eax 1/r32/ecx
 7350     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7351     05/add-to-eax 4/imm32
 7352     # var slice/ecx: slice = {eax, ecx}
 7353     51/push-ecx
 7354     50/push-eax
 7355     89/<- %ecx 4/r32/esp
 7356     # _test-input-stream contains "int"
 7357     (clear-stream _test-input-stream)
 7358     (write _test-input-stream "int")
 7359     # var v/edx: (handle var)
 7360     68/push 0/imm32
 7361     68/push 0/imm32
 7362     89/<- %edx 4/r32/esp
 7363     #
 7364     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7365     # var v-addr/edx: (addr var) = lookup(v)
 7366     (lookup *edx *(edx+4))  # => eax
 7367     89/<- %edx 0/r32/eax
 7368     # check v-addr->name
 7369     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7370     (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
 7371     # check v-addr->type
 7372     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7373     (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
 7374     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
 7375     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
 7376     # . epilogue
 7377     89/<- %esp 5/r32/ebp
 7378     5d/pop-to-ebp
 7379     c3/return
 7380 
 7381 test-parse-var-with-type-and-register:
 7382     # . prologue
 7383     55/push-ebp
 7384     89/<- %ebp 4/r32/esp
 7385     # (eax..ecx) = "x/eax:"
 7386     b8/copy-to-eax "x/eax:"/imm32
 7387     8b/-> *eax 1/r32/ecx
 7388     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7389     05/add-to-eax 4/imm32
 7390     # var slice/ecx: slice = {eax, ecx}
 7391     51/push-ecx
 7392     50/push-eax
 7393     89/<- %ecx 4/r32/esp
 7394     # _test-input-stream contains "int"
 7395     (clear-stream _test-input-stream)
 7396     (write _test-input-stream "int")
 7397     # var v/edx: (handle var)
 7398     68/push 0/imm32
 7399     68/push 0/imm32
 7400     89/<- %edx 4/r32/esp
 7401     #
 7402     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7403     # var v-addr/edx: (addr var) = lookup(v)
 7404     (lookup *edx *(edx+4))  # => eax
 7405     89/<- %edx 0/r32/eax
 7406     # check v-addr->name
 7407     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7408     (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
 7409     # check v-addr->register
 7410     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 7411     (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
 7412     # check v-addr->type
 7413     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7414     (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
 7415     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
 7416     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
 7417     # . epilogue
 7418     89/<- %esp 5/r32/ebp
 7419     5d/pop-to-ebp
 7420     c3/return
 7421 
 7422 test-parse-var-with-trailing-characters:
 7423     # . prologue
 7424     55/push-ebp
 7425     89/<- %ebp 4/r32/esp
 7426     # (eax..ecx) = "x:"
 7427     b8/copy-to-eax "x:"/imm32
 7428     8b/-> *eax 1/r32/ecx
 7429     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7430     05/add-to-eax 4/imm32
 7431     # var slice/ecx: slice = {eax, ecx}
 7432     51/push-ecx
 7433     50/push-eax
 7434     89/<- %ecx 4/r32/esp
 7435     # _test-input-stream contains "int,"
 7436     (clear-stream _test-input-stream)
 7437     (write _test-input-stream "int,")
 7438     # var v/edx: (handle var)
 7439     68/push 0/imm32
 7440     68/push 0/imm32
 7441     89/<- %edx 4/r32/esp
 7442     #
 7443     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7444     # var v-addr/edx: (addr var) = lookup(v)
 7445     (lookup *edx *(edx+4))  # => eax
 7446     89/<- %edx 0/r32/eax
 7447     # check v-addr->name
 7448     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7449     (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
 7450     # check v-addr->register
 7451     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
 7452     # check v-addr->type
 7453     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7454     (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
 7455     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
 7456     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
 7457     # . epilogue
 7458     89/<- %esp 5/r32/ebp
 7459     5d/pop-to-ebp
 7460     c3/return
 7461 
 7462 test-parse-var-with-register-and-trailing-characters:
 7463     # . prologue
 7464     55/push-ebp
 7465     89/<- %ebp 4/r32/esp
 7466     # (eax..ecx) = "x/eax:"
 7467     b8/copy-to-eax "x/eax:"/imm32
 7468     8b/-> *eax 1/r32/ecx
 7469     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7470     05/add-to-eax 4/imm32
 7471     # var slice/ecx: slice = {eax, ecx}
 7472     51/push-ecx
 7473     50/push-eax
 7474     89/<- %ecx 4/r32/esp
 7475     # _test-input-stream contains "int,"
 7476     (clear-stream _test-input-stream)
 7477     (write _test-input-stream "int,")
 7478     # var v/edx: (handle var)
 7479     68/push 0/imm32
 7480     68/push 0/imm32
 7481     89/<- %edx 4/r32/esp
 7482     #
 7483     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7484     # var v-addr/edx: (addr var) = lookup(v)
 7485     (lookup *edx *(edx+4))  # => eax
 7486     89/<- %edx 0/r32/eax
 7487     # check v-addr->name
 7488     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7489     (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
 7490     # check v-addr->register
 7491     (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
 7492     (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
 7493     # check v-addr->type
 7494     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7495     (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
 7496     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
 7497     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
 7498     # . epilogue
 7499     89/<- %esp 5/r32/ebp
 7500     5d/pop-to-ebp
 7501     c3/return
 7502 
 7503 test-parse-var-with-compound-type:
 7504     # . prologue
 7505     55/push-ebp
 7506     89/<- %ebp 4/r32/esp
 7507     # (eax..ecx) = "x:"
 7508     b8/copy-to-eax "x:"/imm32
 7509     8b/-> *eax 1/r32/ecx
 7510     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7511     05/add-to-eax 4/imm32
 7512     # var slice/ecx: slice = {eax, ecx}
 7513     51/push-ecx
 7514     50/push-eax
 7515     89/<- %ecx 4/r32/esp
 7516     # _test-input-stream contains "(addr int)"
 7517     (clear-stream _test-input-stream)
 7518     (write _test-input-stream "(addr int)")
 7519     # var v/edx: (handle var)
 7520     68/push 0/imm32
 7521     68/push 0/imm32
 7522     89/<- %edx 4/r32/esp
 7523     #
 7524     (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
 7525     # var v-addr/edx: (addr var) = lookup(v)
 7526     (lookup *edx *(edx+4))  # => eax
 7527     89/<- %edx 0/r32/eax
 7528     # check v-addr->name
 7529     (lookup *edx *(edx+4))  # Var-name Var-name => eax
 7530     (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
 7531     # check v-addr->register
 7532     (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
 7533     # - check v-addr->type
 7534     # var type/edx: (addr type-tree) = var->type
 7535     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
 7536     89/<- %edx 0/r32/eax
 7537     # type is a non-atom
 7538     (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
 7539     # type->left == atom(addr)
 7540     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
 7541     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
 7542     (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
 7543     # type->right->left == atom(int)
 7544     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
 7545     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 7546     (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
 7547     (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
 7548     # type->right->right == null
 7549     (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
 7550     # . epilogue
 7551     89/<- %esp 5/r32/ebp
 7552     5d/pop-to-ebp
 7553     c3/return
 7554 
 7555 # identifier starts with a letter or '$' or '_'
 7556 # no constraints at the moment on later letters
 7557 # all we really want to do so far is exclude '{', '}' and '->'
 7558 is-identifier?:  # in: (addr slice) -> result/eax: boolean
 7559     # . prologue
 7560     55/push-ebp
 7561     89/<- %ebp 4/r32/esp
 7562     # if (slice-empty?(in)) return false
 7563     (slice-empty? *(ebp+8))  # => eax
 7564     3d/compare-eax-and 0/imm32/false
 7565     75/jump-if-!= $is-identifier?:false/disp8
 7566     # var c/eax: byte = *in->start
 7567     8b/-> *(ebp+8) 0/r32/eax
 7568     8b/-> *eax 0/r32/eax
 7569     8a/copy-byte *eax 0/r32/AL
 7570     81 4/subop/and %eax 0xff/imm32
 7571     # if (c == '$') return true
 7572     3d/compare-eax-and 0x24/imm32/$
 7573     74/jump-if-= $is-identifier?:true/disp8
 7574     # if (c == '_') return true
 7575     3d/compare-eax-and 0x5f/imm32/_
 7576     74/jump-if-= $is-identifier?:true/disp8
 7577     # drop case
 7578     25/and-eax-with 0x5f/imm32
 7579     # if (c < 'A') return false
 7580     3d/compare-eax-and 0x41/imm32/A
 7581     7c/jump-if-< $is-identifier?:false/disp8
 7582     # if (c > 'Z') return false
 7583     3d/compare-eax-and 0x5a/imm32/Z
 7584     7f/jump-if-> $is-identifier?:false/disp8
 7585     # otherwise return true
 7586 $is-identifier?:true:
 7587     b8/copy-to-eax 1/imm32/true
 7588     eb/jump $is-identifier?:end/disp8
 7589 $is-identifier?:false:
 7590     b8/copy-to-eax 0/imm32/false
 7591 $is-identifier?:end:
 7592     # . epilogue
 7593     89/<- %esp 5/r32/ebp
 7594     5d/pop-to-ebp
 7595     c3/return
 7596 
 7597 test-is-identifier-dollar:
 7598     # . prologue
 7599     55/push-ebp
 7600     89/<- %ebp 4/r32/esp
 7601     # (eax..ecx) = "$a"
 7602     b8/copy-to-eax "$a"/imm32
 7603     8b/-> *eax 1/r32/ecx
 7604     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7605     05/add-to-eax 4/imm32
 7606     # var slice/ecx: slice = {eax, ecx}
 7607     51/push-ecx
 7608     50/push-eax
 7609     89/<- %ecx 4/r32/esp
 7610     #
 7611     (is-identifier? %ecx)
 7612     (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
 7613     # . epilogue
 7614     89/<- %esp 5/r32/ebp
 7615     5d/pop-to-ebp
 7616     c3/return
 7617 
 7618 test-is-identifier-underscore:
 7619     # . prologue
 7620     55/push-ebp
 7621     89/<- %ebp 4/r32/esp
 7622     # (eax..ecx) = "_a"
 7623     b8/copy-to-eax "_a"/imm32
 7624     8b/-> *eax 1/r32/ecx
 7625     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7626     05/add-to-eax 4/imm32
 7627     # var slice/ecx: slice = {eax, ecx}
 7628     51/push-ecx
 7629     50/push-eax
 7630     89/<- %ecx 4/r32/esp
 7631     #
 7632     (is-identifier? %ecx)
 7633     (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
 7634     # . epilogue
 7635     89/<- %esp 5/r32/ebp
 7636     5d/pop-to-ebp
 7637     c3/return
 7638 
 7639 test-is-identifier-a:
 7640     # . prologue
 7641     55/push-ebp
 7642     89/<- %ebp 4/r32/esp
 7643     # (eax..ecx) = "a$"
 7644     b8/copy-to-eax "a$"/imm32
 7645     8b/-> *eax 1/r32/ecx
 7646     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7647     05/add-to-eax 4/imm32
 7648     # var slice/ecx: slice = {eax, ecx}
 7649     51/push-ecx
 7650     50/push-eax
 7651     89/<- %ecx 4/r32/esp
 7652     #
 7653     (is-identifier? %ecx)
 7654     (check-ints-equal %eax 1 "F - test-is-identifier-a")
 7655     # . epilogue
 7656     89/<- %esp 5/r32/ebp
 7657     5d/pop-to-ebp
 7658     c3/return
 7659 
 7660 test-is-identifier-z:
 7661     # . prologue
 7662     55/push-ebp
 7663     89/<- %ebp 4/r32/esp
 7664     # (eax..ecx) = "z$"
 7665     b8/copy-to-eax "z$"/imm32
 7666     8b/-> *eax 1/r32/ecx
 7667     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7668     05/add-to-eax 4/imm32
 7669     # var slice/ecx: slice = {eax, ecx}
 7670     51/push-ecx
 7671     50/push-eax
 7672     89/<- %ecx 4/r32/esp
 7673     #
 7674     (is-identifier? %ecx)
 7675     (check-ints-equal %eax 1 "F - test-is-identifier-z")
 7676     # . epilogue
 7677     89/<- %esp 5/r32/ebp
 7678     5d/pop-to-ebp
 7679     c3/return
 7680 
 7681 test-is-identifier-A:
 7682     # . prologue
 7683     55/push-ebp
 7684     89/<- %ebp 4/r32/esp
 7685     # (eax..ecx) = "A$"
 7686     b8/copy-to-eax "A$"/imm32
 7687     8b/-> *eax 1/r32/ecx
 7688     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7689     05/add-to-eax 4/imm32
 7690     # var slice/ecx: slice = {eax, ecx}
 7691     51/push-ecx
 7692     50/push-eax
 7693     89/<- %ecx 4/r32/esp
 7694     #
 7695     (is-identifier? %ecx)
 7696     (check-ints-equal %eax 1 "F - test-is-identifier-A")
 7697     # . epilogue
 7698     89/<- %esp 5/r32/ebp
 7699     5d/pop-to-ebp
 7700     c3/return
 7701 
 7702 test-is-identifier-Z:
 7703     # . prologue
 7704     55/push-ebp
 7705     89/<- %ebp 4/r32/esp
 7706     # (eax..ecx) = "Z$"
 7707     b8/copy-to-eax "Z$"/imm32
 7708     8b/-> *eax 1/r32/ecx
 7709     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7710     05/add-to-eax 4/imm32
 7711     # var slice/ecx: slice = {eax, ecx}
 7712     51/push-ecx
 7713     50/push-eax
 7714     89/<- %ecx 4/r32/esp
 7715     #
 7716     (is-identifier? %ecx)
 7717     (check-ints-equal %eax 1 "F - test-is-identifier-Z")
 7718     # . epilogue
 7719     89/<- %esp 5/r32/ebp
 7720     5d/pop-to-ebp
 7721     c3/return
 7722 
 7723 test-is-identifier-at:
 7724     # character before 'A' is invalid
 7725     # . prologue
 7726     55/push-ebp
 7727     89/<- %ebp 4/r32/esp
 7728     # (eax..ecx) = "@a"
 7729     b8/copy-to-eax "@a"/imm32
 7730     8b/-> *eax 1/r32/ecx
 7731     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7732     05/add-to-eax 4/imm32
 7733     # var slice/ecx: slice = {eax, ecx}
 7734     51/push-ecx
 7735     50/push-eax
 7736     89/<- %ecx 4/r32/esp
 7737     #
 7738     (is-identifier? %ecx)
 7739     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 7740     # . epilogue
 7741     89/<- %esp 5/r32/ebp
 7742     5d/pop-to-ebp
 7743     c3/return
 7744 
 7745 test-is-identifier-square-bracket:
 7746     # character after 'Z' is invalid
 7747     # . prologue
 7748     55/push-ebp
 7749     89/<- %ebp 4/r32/esp
 7750     # (eax..ecx) = "[a"
 7751     b8/copy-to-eax "[a"/imm32
 7752     8b/-> *eax 1/r32/ecx
 7753     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7754     05/add-to-eax 4/imm32
 7755     # var slice/ecx: slice = {eax, ecx}
 7756     51/push-ecx
 7757     50/push-eax
 7758     89/<- %ecx 4/r32/esp
 7759     #
 7760     (is-identifier? %ecx)
 7761     (check-ints-equal %eax 0 "F - test-is-identifier-@")
 7762     # . epilogue
 7763     89/<- %esp 5/r32/ebp
 7764     5d/pop-to-ebp
 7765     c3/return
 7766 
 7767 test-is-identifier-backtick:
 7768     # character before 'a' is invalid
 7769     # . prologue
 7770     55/push-ebp
 7771     89/<- %ebp 4/r32/esp
 7772     # (eax..ecx) = "`a"
 7773     b8/copy-to-eax "`a"/imm32
 7774     8b/-> *eax 1/r32/ecx
 7775     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7776     05/add-to-eax 4/imm32
 7777     # var slice/ecx: slice = {eax, ecx}
 7778     51/push-ecx
 7779     50/push-eax
 7780     89/<- %ecx 4/r32/esp
 7781     #
 7782     (is-identifier? %ecx)
 7783     (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
 7784     # . epilogue
 7785     89/<- %esp 5/r32/ebp
 7786     5d/pop-to-ebp
 7787     c3/return
 7788 
 7789 test-is-identifier-curly-brace-open:
 7790     # character after 'z' is invalid; also used for blocks
 7791     # . prologue
 7792     55/push-ebp
 7793     89/<- %ebp 4/r32/esp
 7794     # (eax..ecx) = "{a"
 7795     b8/copy-to-eax "{a"/imm32
 7796     8b/-> *eax 1/r32/ecx
 7797     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7798     05/add-to-eax 4/imm32
 7799     # var slice/ecx: slice = {eax, ecx}
 7800     51/push-ecx
 7801     50/push-eax
 7802     89/<- %ecx 4/r32/esp
 7803     #
 7804     (is-identifier? %ecx)
 7805     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
 7806     # . epilogue
 7807     89/<- %esp 5/r32/ebp
 7808     5d/pop-to-ebp
 7809     c3/return
 7810 
 7811 test-is-identifier-curly-brace-close:
 7812     # . prologue
 7813     55/push-ebp
 7814     89/<- %ebp 4/r32/esp
 7815     # (eax..ecx) = "}a"
 7816     b8/copy-to-eax "}a"/imm32
 7817     8b/-> *eax 1/r32/ecx
 7818     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7819     05/add-to-eax 4/imm32
 7820     # var slice/ecx: slice = {eax, ecx}
 7821     51/push-ecx
 7822     50/push-eax
 7823     89/<- %ecx 4/r32/esp
 7824     #
 7825     (is-identifier? %ecx)
 7826     (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
 7827     # . epilogue
 7828     89/<- %esp 5/r32/ebp
 7829     5d/pop-to-ebp
 7830     c3/return
 7831 
 7832 test-is-identifier-hyphen:
 7833     # disallow leading '-' since '->' has special meaning
 7834     # . prologue
 7835     55/push-ebp
 7836     89/<- %ebp 4/r32/esp
 7837     # (eax..ecx) = "-a"
 7838     b8/copy-to-eax "-a"/imm32
 7839     8b/-> *eax 1/r32/ecx
 7840     8d/copy-address *(eax+ecx+4) 1/r32/ecx
 7841     05/add-to-eax 4/imm32
 7842     # var slice/ecx: slice = {eax, ecx}
 7843     51/push-ecx
 7844     50/push-eax
 7845     89/<- %ecx 4/r32/esp
 7846     #
 7847     (is-identifier? %ecx)
 7848     (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
 7849     # . epilogue
 7850     89/<- %esp 5/r32/ebp
 7851     5d/pop-to-ebp
 7852     c3/return
 7853 
 7854 populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
 7855     # . prologue
 7856     55/push-ebp
 7857     89/<- %ebp 4/r32/esp
 7858     # . save registers
 7859     50/push-eax
 7860     56/push-esi
 7861     57/push-edi
 7862     # esi = in
 7863     8b/-> *(ebp+8) 6/r32/esi
 7864     # edi = out
 7865     8b/-> *(ebp+0xc) 7/r32/edi
 7866     # initialize some global state
 7867     c7 0/subop/copy *Curr-block-depth 1/imm32
 7868     # parse-mu-block(in, vars, out, out->body)
 7869     8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
 7870     (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
 7871 $populate-mu-function-body:end:
 7872     # . restore registers
 7873     5f/pop-to-edi
 7874     5e/pop-to-esi
 7875     58/pop-to-eax
 7876     # . epilogue
 7877     89/<- %esp 5/r32/ebp
 7878     5d/pop-to-ebp
 7879     c3/return
 7880 
 7881 # parses a block, assuming that the leading '{' has already been read by the caller
 7882 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)
 7883     # pseudocode:
 7884     #   var line: (stream byte 512)
 7885     #   var word-slice: slice
 7886     #   allocate(Heap, Stmt-size, out)
 7887     #   var out-addr: (addr block) = lookup(*out)
 7888     #   out-addr->tag = 0/block
 7889     #   out-addr->var = some unique name
 7890     #   push(vars, {out-addr->var, false})
 7891     #   while true                                  # line loop
 7892     #     clear-stream(line)
 7893     #     read-line-buffered(in, line)
 7894     #     if (line->write == 0) break               # end of file
 7895     #     word-slice = next-mu-token(line)
 7896     #     if slice-empty?(word-slice)               # end of line
 7897     #       continue
 7898     #     else if slice-starts-with?(word-slice, "#")
 7899     #       continue
 7900     #     else if slice-equal?(word-slice, "{")
 7901     #       assert(no-tokens-in(line))
 7902     #       block = parse-mu-block(in, vars, fn)
 7903     #       append-to-block(out-addr, block)
 7904     #     else if slice-equal?(word-slice, "}")
 7905     #       break
 7906     #     else if slice-ends-with?(word-slice, ":")
 7907     #       # TODO: error-check the rest of 'line'
 7908     #       --word-slice->end to skip ':'
 7909     #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
 7910     #       append-to-block(out-addr, named-block)
 7911     #     else if slice-equal?(word-slice, "var")
 7912     #       var-def = parse-mu-var-def(line, vars, fn)
 7913     #       append-to-block(out-addr, var-def)
 7914     #     else
 7915     #       stmt = parse-mu-stmt(line, vars, fn)
 7916     #       append-to-block(out-addr, stmt)
 7917     #   pop(vars)
 7918     #
 7919     # . prologue
 7920     55/push-ebp
 7921     89/<- %ebp 4/r32/esp
 7922     # . save registers
 7923     50/push-eax
 7924     51/push-ecx
 7925     52/push-edx
 7926     53/push-ebx
 7927     57/push-edi
 7928     # var line/ecx: (stream byte 512)
 7929     81 5/subop/subtract %esp 0x200/imm32
 7930     68/push 0x200/imm32/size
 7931     68/push 0/imm32/read
 7932     68/push 0/imm32/write
 7933     89/<- %ecx 4/r32/esp
 7934     # var word-slice/edx: slice
 7935     68/push 0/imm32/end
 7936     68/push 0/imm32/start
 7937     89/<- %edx 4/r32/esp
 7938     # allocate into out
 7939     (allocate Heap *Stmt-size *(ebp+0x14))
 7940     # var out-addr/edi: (addr block) = lookup(*out)
 7941     8b/-> *(ebp+0x14) 7/r32/edi
 7942     (lookup *edi *(edi+4))  # => eax
 7943     89/<- %edi 0/r32/eax
 7944     # out-addr->tag is 0 (block) by default
 7945     # set out-addr->var
 7946     8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
 7947     (new-block-name *(ebp+0x10) %eax)
 7948     # push(vars, out-addr->var)
 7949     (push *(ebp+0xc) *(edi+0xc))  # Block-var
 7950     (push *(ebp+0xc) *(edi+0x10))  # Block-var
 7951     (push *(ebp+0xc) 0)  # false
 7952     # increment *Curr-block-depth
 7953     ff 0/subop/increment *Curr-block-depth
 7954     {
 7955 $parse-mu-block:line-loop:
 7956       # line = read-line-buffered(in)
 7957       (clear-stream %ecx)
 7958       (read-line-buffered *(ebp+8) %ecx)
 7959 #?       (write-buffered Stderr "line: ")
 7960 #?       (write-stream-data Stderr %ecx)
 7961 #? #?       (write-buffered Stderr Newline)  # line has its own newline
 7962 #?       (flush Stderr)
 7963 #?       (rewind-stream %ecx)
 7964       # if (line->write == 0) break
 7965       81 7/subop/compare *ecx 0/imm32
 7966       0f 84/jump-if-= break/disp32
 7967 #?       (write-buffered Stderr "vars:\n")
 7968 #?       (dump-vars *(ebp+0xc))
 7969       # word-slice = next-mu-token(line)
 7970       (next-mu-token %ecx %edx)
 7971 #?       (write-buffered Stderr "word: ")
 7972 #?       (write-slice-buffered Stderr %edx)
 7973 #?       (write-buffered Stderr Newline)
 7974 #?       (flush Stderr)
 7975       # if slice-empty?(word-slice) continue
 7976       (slice-empty? %edx)
 7977       3d/compare-eax-and 0/imm32/false
 7978       0f 85/jump-if-!= loop/disp32
 7979       # if (slice-starts-with?(word-slice, '#') continue
 7980       # . eax = *word-slice->start
 7981       8b/-> *edx 0/r32/eax
 7982       8a/copy-byte *eax 0/r32/AL
 7983       81 4/subop/and %eax 0xff/imm32
 7984       # . if (eax == '#') continue
 7985       3d/compare-eax-and 0x23/imm32/hash
 7986       0f 84/jump-if-= loop/disp32
 7987       # if slice-equal?(word-slice, "{")
 7988       {
 7989 $parse-mu-block:check-for-block:
 7990         (slice-equal? %edx "{")
 7991         3d/compare-eax-and 0/imm32/false
 7992         74/jump-if-= break/disp8
 7993         (check-no-tokens-left %ecx)
 7994         # parse new block and append
 7995         # . var tmp/eax: (handle block)
 7996         68/push 0/imm32
 7997         68/push 0/imm32
 7998         89/<- %eax 4/r32/esp
 7999         # .
 8000         (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8001         (append-to-block Heap %edi  *eax *(eax+4))
 8002         # . reclaim tmp
 8003         81 0/subop/add %esp 8/imm32
 8004         # .
 8005         e9/jump $parse-mu-block:line-loop/disp32
 8006       }
 8007       # if slice-equal?(word-slice, "}") break
 8008 $parse-mu-block:check-for-end:
 8009       (slice-equal? %edx "}")
 8010       3d/compare-eax-and 0/imm32/false
 8011       0f 85/jump-if-!= break/disp32
 8012       # if slice-ends-with?(word-slice, ":") parse named block and append
 8013       {
 8014 $parse-mu-block:check-for-named-block:
 8015         # . eax = *(word-slice->end-1)
 8016         8b/-> *(edx+4) 0/r32/eax
 8017         48/decrement-eax
 8018         8a/copy-byte *eax 0/r32/AL
 8019         81 4/subop/and %eax 0xff/imm32
 8020         # . if (eax != ':') break
 8021         3d/compare-eax-and 0x3a/imm32/colon
 8022         0f 85/jump-if-!= break/disp32
 8023         # TODO: error-check the rest of 'line'
 8024         #
 8025         # skip ':'
 8026         ff 1/subop/decrement *(edx+4)  # Slice-end
 8027         # var tmp/eax: (handle block)
 8028         68/push 0/imm32
 8029         68/push 0/imm32
 8030         89/<- %eax 4/r32/esp
 8031         #
 8032         (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8033         (append-to-block Heap %edi  *eax *(eax+4))
 8034         # reclaim tmp
 8035         81 0/subop/add %esp 8/imm32
 8036         #
 8037         e9/jump $parse-mu-block:line-loop/disp32
 8038       }
 8039       # if slice-equal?(word-slice, "var")
 8040       {
 8041 $parse-mu-block:check-for-var:
 8042         (slice-equal? %edx "var")
 8043         3d/compare-eax-and 0/imm32/false
 8044         74/jump-if-= break/disp8
 8045         # var tmp/eax: (handle block)
 8046         68/push 0/imm32
 8047         68/push 0/imm32
 8048         89/<- %eax 4/r32/esp
 8049         #
 8050         (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8051         (append-to-block Heap %edi  *eax *(eax+4))
 8052         # reclaim tmp
 8053         81 0/subop/add %esp 8/imm32
 8054         #
 8055         e9/jump $parse-mu-block:line-loop/disp32
 8056       }
 8057 $parse-mu-block:regular-stmt:
 8058       # otherwise
 8059       # var tmp/eax: (handle block)
 8060       68/push 0/imm32
 8061       68/push 0/imm32
 8062       89/<- %eax 4/r32/esp
 8063       #
 8064       (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
 8065       (append-to-block Heap %edi  *eax *(eax+4))
 8066       # reclaim tmp
 8067       81 0/subop/add %esp 8/imm32
 8068       #
 8069       e9/jump loop/disp32
 8070     } # end line loop
 8071     (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
 8072     # decrement *Curr-block-depth
 8073     ff 1/subop/decrement *Curr-block-depth
 8074     # pop(vars)
 8075     (pop *(ebp+0xc))  # => eax
 8076     (pop *(ebp+0xc))  # => eax
 8077     (pop *(ebp+0xc))  # => eax
 8078 $parse-mu-block:end:
 8079     # . reclaim locals
 8080     81 0/subop/add %esp 0x214/imm32
 8081     # . restore registers
 8082     5f/pop-to-edi
 8083     5b/pop-to-ebx
 8084     5a/pop-to-edx
 8085     59/pop-to-ecx
 8086     58/pop-to-eax
 8087     # . epilogue
 8088     89/<- %esp 5/r32/ebp
 8089     5d/pop-to-ebp
 8090     c3/return
 8091 
 8092 $parse-mu-block:abort:
 8093     # error("'{' or '}' should be on its own line, but got '")
 8094     (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
 8095     (rewind-stream %ecx)
 8096     (write-stream-data *(ebp+0x18) %ecx)
 8097     (write-buffered *(ebp+0x18) "'\n")
 8098     (flush *(ebp+0x18))
 8099     (stop *(ebp+0x1c) 1)
 8100     # never gets here
 8101 
 8102 new-block-name:  # fn: (addr function), out: (addr handle var)
 8103     # . prologue
 8104     55/push-ebp
 8105     89/<- %ebp 4/r32/esp
 8106     # . save registers
 8107     50/push-eax
 8108     51/push-ecx
 8109     52/push-edx
 8110     # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
 8111     8b/-> *(ebp+8) 0/r32/eax
 8112     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8113     8b/-> *eax 0/r32/eax  # String-size
 8114     05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
 8115     89/<- %ecx 0/r32/eax
 8116     # var name/edx: (stream byte n)
 8117     29/subtract-from %esp 1/r32/ecx
 8118     ff 6/subop/push %ecx
 8119     68/push 0/imm32/read
 8120     68/push 0/imm32/write
 8121     89/<- %edx 4/r32/esp
 8122     (clear-stream %edx)
 8123     # eax = fn->name
 8124     8b/-> *(ebp+8) 0/r32/eax
 8125     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8126     # construct result using Next-block-index (and increment it)
 8127     (write %edx "$")
 8128     (write %edx %eax)
 8129     (write %edx ":")
 8130     (write-int32-hex %edx *Next-block-index)
 8131     ff 0/subop/increment *Next-block-index
 8132     # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
 8133     # . eax = name->write
 8134     8b/-> *edx 0/r32/eax
 8135     # . edx = name->data
 8136     8d/copy-address *(edx+0xc) 2/r32/edx
 8137     # . eax = name->write + name->data
 8138     01/add-to %eax 2/r32/edx
 8139     # . push {edx, eax}
 8140     ff 6/subop/push %eax
 8141     ff 6/subop/push %edx
 8142     89/<- %eax 4/r32/esp
 8143     # out = new literal(s)
 8144     (new-literal Heap %eax *(ebp+0xc))
 8145 #?     8b/-> *(ebp+0xc) 0/r32/eax
 8146 #?     (write-buffered Stderr "type allocid in caller after new-literal: ")
 8147 #?     (write-int32-hex-buffered Stderr *(eax+8))
 8148 #?     (write-buffered Stderr " for var ")
 8149 #?     (write-int32-hex-buffered Stderr %eax)
 8150 #?     (write-buffered Stderr Newline)
 8151 #?     (flush Stderr)
 8152 $new-block-name:end:
 8153     # . reclaim locals
 8154     81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
 8155     81 0/subop/add %ecx 8/imm32  # slice
 8156     01/add-to %esp 1/r32/ecx
 8157     # . restore registers
 8158     5a/pop-to-edx
 8159     59/pop-to-ecx
 8160     58/pop-to-eax
 8161     # . epilogue
 8162     89/<- %esp 5/r32/ebp
 8163     5d/pop-to-ebp
 8164     c3/return
 8165 
 8166 check-no-tokens-left:  # line: (addr stream byte)
 8167     # . prologue
 8168     55/push-ebp
 8169     89/<- %ebp 4/r32/esp
 8170     # . save registers
 8171     50/push-eax
 8172     51/push-ecx
 8173     # var s/ecx: slice
 8174     68/push 0/imm32/end
 8175     68/push 0/imm32/start
 8176     89/<- %ecx 4/r32/esp
 8177     #
 8178     (next-mu-token *(ebp+8) %ecx)
 8179     # if slice-empty?(s) return
 8180     (slice-empty? %ecx)
 8181     3d/compare-eax-and 0/imm32/false
 8182     75/jump-if-!= $check-no-tokens-left:end/disp8
 8183     # if (slice-starts-with?(s, '#') return
 8184     # . eax = *s->start
 8185     8b/-> *edx 0/r32/eax
 8186     8a/copy-byte *eax 0/r32/AL
 8187     81 4/subop/and %eax 0xff/imm32
 8188     # . if (eax == '#') continue
 8189     3d/compare-eax-and 0x23/imm32/hash
 8190     74/jump-if-= $check-no-tokens-left:end/disp8
 8191     # abort
 8192     (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
 8193     (rewind-stream %ecx)
 8194     (write-stream 2 %ecx)
 8195     (write-buffered Stderr "'\n")
 8196     (flush Stderr)
 8197     # . syscall(exit, 1)
 8198     bb/copy-to-ebx  1/imm32
 8199     e8/call syscall_exit/disp32
 8200     # never gets here
 8201 $check-no-tokens-left:end:
 8202     # . reclaim locals
 8203     81 0/subop/add %esp 8/imm32
 8204     # . restore registers
 8205     59/pop-to-ecx
 8206     58/pop-to-eax
 8207     # . epilogue
 8208     89/<- %esp 5/r32/ebp
 8209     5d/pop-to-ebp
 8210     c3/return
 8211 
 8212 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)
 8213     # pseudocode:
 8214     #   var v: (handle var)
 8215     #   new-literal(name, v)
 8216     #   push(vars, {v, false})
 8217     #   parse-mu-block(in, vars, fn, out)
 8218     #   pop(vars)
 8219     #   out->tag = block
 8220     #   out->var = v
 8221     #
 8222     # . prologue
 8223     55/push-ebp
 8224     89/<- %ebp 4/r32/esp
 8225     # . save registers
 8226     50/push-eax
 8227     51/push-ecx
 8228     57/push-edi
 8229     # var v/ecx: (handle var)
 8230     68/push 0/imm32
 8231     68/push 0/imm32
 8232     89/<- %ecx 4/r32/esp
 8233     #
 8234     (new-literal Heap *(ebp+8) %ecx)
 8235     # push(vars, v)
 8236     (push *(ebp+0x10) *ecx)
 8237     (push *(ebp+0x10) *(ecx+4))
 8238     (push *(ebp+0x10) 0)  # false
 8239     #
 8240     (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
 8241     # pop v off vars
 8242     (pop *(ebp+0x10))  # => eax
 8243     (pop *(ebp+0x10))  # => eax
 8244     (pop *(ebp+0x10))  # => eax
 8245     # var out-addr/edi: (addr stmt) = lookup(*out)
 8246     8b/-> *(ebp+0x18) 7/r32/edi
 8247     (lookup *edi *(edi+4))  # => eax
 8248     89/<- %edi 0/r32/eax
 8249     # out-addr->tag = named-block
 8250     c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
 8251     # out-addr->var = v
 8252     8b/-> *ecx 0/r32/eax
 8253     89/<- *(edi+0xc) 0/r32/eax  # Block-var
 8254     8b/-> *(ecx+4) 0/r32/eax
 8255     89/<- *(edi+0x10) 0/r32/eax  # Block-var
 8256 $parse-mu-named-block:end:
 8257     # . reclaim locals
 8258     81 0/subop/add %esp 8/imm32
 8259     # . restore registers
 8260     5f/pop-to-edi
 8261     59/pop-to-ecx
 8262     58/pop-to-eax
 8263     # . epilogue
 8264     89/<- %esp 5/r32/ebp
 8265     5d/pop-to-ebp
 8266     c3/return
 8267 
 8268 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)
 8269     # . prologue
 8270     55/push-ebp
 8271     89/<- %ebp 4/r32/esp
 8272     # . save registers
 8273     50/push-eax
 8274     51/push-ecx
 8275     52/push-edx
 8276     53/push-ebx
 8277     57/push-edi
 8278     # edi = out
 8279     8b/-> *(ebp+0x10) 7/r32/edi
 8280     # var word-slice/ecx: slice
 8281     68/push 0/imm32/end
 8282     68/push 0/imm32/start
 8283     89/<- %ecx 4/r32/esp
 8284     # var v/edx: (handle var)
 8285     68/push 0/imm32
 8286     68/push 0/imm32
 8287     89/<- %edx 4/r32/esp
 8288     # v = parse-var-with-type(next-mu-token(line))
 8289     (next-mu-token *(ebp+8) %ecx)
 8290     (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
 8291     # var v-addr/eax: (addr var)
 8292     (lookup *edx *(edx+4))  # => eax
 8293     # v->block-depth = *Curr-block-depth
 8294     8b/-> *Curr-block-depth 3/r32/ebx
 8295     89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
 8296     # either v has no register and there's no more to this line
 8297     8b/-> *(eax+0x18) 0/r32/eax  # Var-register
 8298     3d/compare-eax-and 0/imm32
 8299     {
 8300       75/jump-if-!= break/disp8
 8301       # TODO: disallow vars of type 'byte' on the stack
 8302       # ensure that there's nothing else on this line
 8303       (next-mu-token *(ebp+8) %ecx)
 8304       (slice-empty? %ecx)  # => eax
 8305       3d/compare-eax-and 0/imm32/false
 8306       0f 84/jump-if-= $parse-mu-var-def:error2/disp32
 8307       #
 8308       (new-var-def Heap  *edx *(edx+4)  %edi)
 8309       e9/jump $parse-mu-var-def:update-vars/disp32
 8310     }
 8311     # or v has a register and there's more to this line
 8312     {
 8313       0f 84/jump-if-= break/disp32
 8314       # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
 8315       # TODO: vars of type 'byte' should only be initialized by clearing to 0
 8316       # ensure that the next word is '<-'
 8317       (next-mu-token *(ebp+8) %ecx)
 8318       (slice-equal? %ecx "<-")  # => eax
 8319       3d/compare-eax-and 0/imm32/false
 8320       0f 84/jump-if-= $parse-mu-var-def:error1/disp32
 8321       #
 8322       (new-reg-var-def Heap  *edx *(edx+4)  %edi)
 8323       (lookup *edi *(edi+4))  # => eax
 8324       (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8325     }
 8326 $parse-mu-var-def:update-vars:
 8327     # push 'v' at end of function
 8328     (push *(ebp+0xc) *edx)
 8329     (push *(ebp+0xc) *(edx+4))
 8330     (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
 8331 $parse-mu-var-def:end:
 8332     # . reclaim locals
 8333     81 0/subop/add %esp 0x10/imm32
 8334     # . restore registers
 8335     5f/pop-to-edi
 8336     5b/pop-to-ebx
 8337     5a/pop-to-edx
 8338     59/pop-to-ecx
 8339     58/pop-to-eax
 8340     # . epilogue
 8341     89/<- %esp 5/r32/ebp
 8342     5d/pop-to-ebp
 8343     c3/return
 8344 
 8345 $parse-mu-var-def:error1:
 8346     (rewind-stream *(ebp+8))
 8347     # error("register variable requires a valid instruction to initialize but got '" line "'\n")
 8348     (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
 8349     (flush *(ebp+0x18))
 8350     (write-stream-data *(ebp+0x18) *(ebp+8))
 8351     (write-buffered *(ebp+0x18) "'\n")
 8352     (flush *(ebp+0x18))
 8353     (stop *(ebp+0x1c) 1)
 8354     # never gets here
 8355 
 8356 $parse-mu-var-def:error2:
 8357     (rewind-stream *(ebp+8))
 8358     # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
 8359     (write-buffered *(ebp+0x18) "fn ")
 8360     8b/-> *(ebp+0x14) 0/r32/eax
 8361     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8362     (write-buffered *(ebp+0x18) %eax)
 8363     (write-buffered *(ebp+0x18) ": var ")
 8364     # var v-addr/eax: (addr var) = lookup(v)
 8365     (lookup *edx *(edx+4))  # => eax
 8366     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 8367     (write-buffered *(ebp+0x18) %eax)
 8368     (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
 8369     (flush *(ebp+0x18))
 8370     (stop *(ebp+0x1c) 1)
 8371     # never gets here
 8372 
 8373 test-parse-mu-var-def:
 8374     # 'var n: int'
 8375     # . prologue
 8376     55/push-ebp
 8377     89/<- %ebp 4/r32/esp
 8378     # setup
 8379     (clear-stream _test-input-stream)
 8380     (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
 8381     c7 0/subop/copy *Curr-block-depth 1/imm32
 8382     # var out/esi: (handle stmt)
 8383     68/push 0/imm32
 8384     68/push 0/imm32
 8385     89/<- %esi 4/r32/esp
 8386     # var vars/ecx: (stack (addr var) 16)
 8387     81 5/subop/subtract %esp 0xc0/imm32
 8388     68/push 0xc0/imm32/size
 8389     68/push 0/imm32/top
 8390     89/<- %ecx 4/r32/esp
 8391     (clear-stack %ecx)
 8392     # convert
 8393     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8394     # var out-addr/esi: (addr stmt)
 8395     (lookup *esi *(esi+4))  # => eax
 8396     89/<- %esi 0/r32/eax
 8397     #
 8398     (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
 8399     # var v/ecx: (addr var) = lookup(out->var)
 8400     (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
 8401     89/<- %ecx 0/r32/eax
 8402     # v->name
 8403     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8404     (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
 8405     # v->register
 8406     (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
 8407     # v->block-depth
 8408     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
 8409     # v->type == int
 8410     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8411     (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
 8412     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
 8413     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
 8414     # . epilogue
 8415     89/<- %esp 5/r32/ebp
 8416     5d/pop-to-ebp
 8417     c3/return
 8418 
 8419 test-parse-mu-reg-var-def:
 8420     # 'var n/eax: int <- copy 0'
 8421     # . prologue
 8422     55/push-ebp
 8423     89/<- %ebp 4/r32/esp
 8424     # setup
 8425     (clear-stream _test-input-stream)
 8426     (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
 8427     c7 0/subop/copy *Curr-block-depth 1/imm32
 8428     # var out/esi: (handle stmt)
 8429     68/push 0/imm32
 8430     68/push 0/imm32
 8431     89/<- %esi 4/r32/esp
 8432     # var vars/ecx: (stack (addr var) 16)
 8433     81 5/subop/subtract %esp 0xc0/imm32
 8434     68/push 0xc0/imm32/size
 8435     68/push 0/imm32/top
 8436     89/<- %ecx 4/r32/esp
 8437     (clear-stack %ecx)
 8438     # convert
 8439     (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
 8440     # var out-addr/esi: (addr stmt)
 8441     (lookup *esi *(esi+4))  # => eax
 8442     89/<- %esi 0/r32/eax
 8443     #
 8444     (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
 8445     # var v/ecx: (addr var) = lookup(out->outputs->value)
 8446     # . eax: (addr stmt-var) = lookup(out->outputs)
 8447     (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
 8448     # .
 8449     (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
 8450     # . eax: (addr var) = lookup(eax->value)
 8451     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 8452     # . ecx = eax
 8453     89/<- %ecx 0/r32/eax
 8454     # v->name
 8455     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8456     (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
 8457     # v->register
 8458     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8459     (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
 8460     # v->block-depth
 8461     (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
 8462     # v->type == int
 8463     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 8464     (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
 8465     (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
 8466     (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
 8467     # . epilogue
 8468     89/<- %esp 5/r32/ebp
 8469     5d/pop-to-ebp
 8470     c3/return
 8471 
 8472 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)
 8473     # Carefully push any outputs on the vars stack _after_ reading the inputs
 8474     # that may conflict with them.
 8475     #
 8476     # The only situation in which outputs are pushed here (when it's not a
 8477     # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
 8478     # output is a function output.
 8479     #
 8480     # pseudocode:
 8481     #   var name: slice
 8482     #   allocate(Heap, Stmt-size, out)
 8483     #   var out-addr: (addr stmt) = lookup(*out)
 8484     #   out-addr->tag = stmt
 8485     #   if stmt-has-outputs?(line)
 8486     #     while true
 8487     #       name = next-mu-token(line)
 8488     #       if (name == '<-') break
 8489     #       assert(is-identifier?(name))
 8490     #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
 8491     #       out-addr->outputs = append(v, out-addr->outputs)
 8492     #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
 8493     #   for output in stmt->outputs:
 8494     #     maybe-define-var(output, vars)
 8495     #
 8496     # . prologue
 8497     55/push-ebp
 8498     89/<- %ebp 4/r32/esp
 8499     # . save registers
 8500     50/push-eax
 8501     51/push-ecx
 8502     52/push-edx
 8503     53/push-ebx
 8504     57/push-edi
 8505     # var name/ecx: slice
 8506     68/push 0/imm32/end
 8507     68/push 0/imm32/start
 8508     89/<- %ecx 4/r32/esp
 8509     # var is-deref?/edx: boolean = false
 8510     ba/copy-to-edx 0/imm32/false
 8511     # var v: (handle var)
 8512     68/push 0/imm32
 8513     68/push 0/imm32
 8514     89/<- %ebx 4/r32/esp
 8515     #
 8516     (allocate Heap *Stmt-size *(ebp+0x14))
 8517     # var out-addr/edi: (addr stmt) = lookup(*out)
 8518     8b/-> *(ebp+0x14) 7/r32/edi
 8519     (lookup *edi *(edi+4))  # => eax
 8520     89/<- %edi 0/r32/eax
 8521     # out-addr->tag = 1/stmt
 8522     c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
 8523     {
 8524       (stmt-has-outputs? *(ebp+8))
 8525       3d/compare-eax-and 0/imm32/false
 8526       0f 84/jump-if-= break/disp32
 8527       {
 8528 $parse-mu-stmt:read-outputs:
 8529         # name = next-mu-token(line)
 8530         (next-mu-token *(ebp+8) %ecx)
 8531         # if slice-empty?(word-slice) break
 8532         (slice-empty? %ecx)  # => eax
 8533         3d/compare-eax-and 0/imm32/false
 8534         0f 85/jump-if-!= break/disp32
 8535         # if (name == "<-") break
 8536         (slice-equal? %ecx "<-")  # => eax
 8537         3d/compare-eax-and 0/imm32/false
 8538         0f 85/jump-if-!= break/disp32
 8539         # is-deref? = false
 8540         ba/copy-to-edx 0/imm32/false
 8541         # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 8542         8b/-> *ecx 0/r32/eax  # Slice-start
 8543         8a/copy-byte *eax 0/r32/AL
 8544         81 4/subop/and %eax 0xff/imm32
 8545         3d/compare-eax-and 0x2a/imm32/asterisk
 8546         {
 8547           75/jump-if-!= break/disp8
 8548           ff 0/subop/increment *ecx
 8549           ba/copy-to-edx 1/imm32/true
 8550         }
 8551         # assert(is-identifier?(name))
 8552         (is-identifier? %ecx)  # => eax
 8553         3d/compare-eax-and 0/imm32/false
 8554         0f 84/jump-if-= $parse-mu-stmt:abort/disp32
 8555         #
 8556         (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
 8557         8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
 8558         (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
 8559         #
 8560         e9/jump loop/disp32
 8561       }
 8562     }
 8563     (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8564 $parse-mu-stmt:define-outputs:
 8565     # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
 8566     (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
 8567     89/<- %edi 0/r32/eax
 8568     {
 8569 $parse-mu-stmt:define-outputs-loop:
 8570       # if (output == null) break
 8571       81 7/subop/compare %edi 0/imm32
 8572       74/jump-if-= break/disp8
 8573       #
 8574       (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
 8575                                                     # and must be in vars. This call will be a no-op, but safe.
 8576       # output = output->next
 8577       (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
 8578       89/<- %edi 0/r32/eax
 8579       #
 8580       eb/jump loop/disp8
 8581     }
 8582 $parse-mu-stmt:end:
 8583     # . reclaim locals
 8584     81 0/subop/add %esp 0x10/imm32
 8585     # . restore registers
 8586     5f/pop-to-edi
 8587     5b/pop-to-ebx
 8588     5a/pop-to-edx
 8589     59/pop-to-ecx
 8590     58/pop-to-eax
 8591     # . epilogue
 8592     89/<- %esp 5/r32/ebp
 8593     5d/pop-to-ebp
 8594     c3/return
 8595 
 8596 $parse-mu-stmt:abort:
 8597     # error("invalid identifier '" name "'\n")
 8598     (write-buffered *(ebp+0x18) "invalid identifier '")
 8599     (write-slice-buffered *(ebp+0x18) %ecx)
 8600     (write-buffered *(ebp+0x18) "'\n")
 8601     (flush *(ebp+0x18))
 8602     (stop *(ebp+0x1c) 1)
 8603     # never gets here
 8604 
 8605 add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8606     # pseudocode:
 8607     #   stmt->name = slice-to-string(next-mu-token(line))
 8608     #   while true
 8609     #     name = next-mu-token(line)
 8610     #     v = lookup-var-or-literal(name)
 8611     #     stmt->inouts = append(v, stmt->inouts)
 8612     #
 8613     # . prologue
 8614     55/push-ebp
 8615     89/<- %ebp 4/r32/esp
 8616     # . save registers
 8617     50/push-eax
 8618     51/push-ecx
 8619     52/push-edx
 8620     53/push-ebx
 8621     56/push-esi
 8622     57/push-edi
 8623     # edi = stmt
 8624     8b/-> *(ebp+8) 7/r32/edi
 8625     # var name/ecx: slice
 8626     68/push 0/imm32/end
 8627     68/push 0/imm32/start
 8628     89/<- %ecx 4/r32/esp
 8629     # var is-deref?/edx: boolean = false
 8630     ba/copy-to-edx 0/imm32/false
 8631     # var v/esi: (handle var)
 8632     68/push 0/imm32
 8633     68/push 0/imm32
 8634     89/<- %esi 4/r32/esp
 8635 $add-operation-and-inputs-to-stmt:read-operation:
 8636     (next-mu-token *(ebp+0xc) %ecx)
 8637     8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
 8638     (slice-to-string Heap %ecx %eax)
 8639     # var is-get?/ebx: boolean = (name == "get")
 8640     (slice-equal? %ecx "get")  # => eax
 8641     89/<- %ebx 0/r32/eax
 8642     {
 8643 $add-operation-and-inputs-to-stmt:read-inouts:
 8644       # name = next-mu-token(line)
 8645       (next-mu-token *(ebp+0xc) %ecx)
 8646       # if slice-empty?(word-slice) break
 8647       (slice-empty? %ecx)  # => eax
 8648       3d/compare-eax-and 0/imm32/false
 8649       0f 85/jump-if-!= break/disp32
 8650       # if (name == "<-") abort
 8651       (slice-equal? %ecx "<-")
 8652       3d/compare-eax-and 0/imm32/false
 8653       0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
 8654       # if (is-get? && second operand) lookup or create offset
 8655       {
 8656         81 7/subop/compare %ebx 0/imm32/false
 8657         74/jump-if-= break/disp8
 8658         (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 8659         3d/compare-eax-and 0/imm32
 8660         74/jump-if-= break/disp8
 8661         (lookup-or-create-constant %eax %ecx %esi)
 8662 #?         (lookup *esi *(esi+4))
 8663 #?         (write-buffered Stderr "creating new output var ")
 8664 #?         (write-int32-hex-buffered Stderr %eax)
 8665 #?         (write-buffered Stderr " for field called ")
 8666 #?         (write-slice-buffered Stderr %ecx)
 8667 #?         (write-buffered Stderr "; var name ")
 8668 #?         (lookup *eax *(eax+4))  # Var-name
 8669 #?         (write-buffered Stderr %eax)
 8670 #?         (write-buffered Stderr Newline)
 8671 #?         (flush Stderr)
 8672         e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
 8673       }
 8674       # is-deref? = false
 8675       ba/copy-to-edx 0/imm32/false
 8676       # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
 8677       8b/-> *ecx 0/r32/eax  # Slice-start
 8678       8a/copy-byte *eax 0/r32/AL
 8679       81 4/subop/and %eax 0xff/imm32
 8680       3d/compare-eax-and 0x2a/imm32/asterisk
 8681       {
 8682         75/jump-if-!= break/disp8
 8683 $add-operation-and-inputs-to-stmt:inout-is-deref:
 8684         ff 0/subop/increment *ecx
 8685         ba/copy-to-edx 1/imm32/true
 8686       }
 8687       (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8688 $add-operation-and-inputs-to-stmt:save-var:
 8689       8d/copy-address *(edi+0xc) 0/r32/eax
 8690       (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
 8691       #
 8692       e9/jump loop/disp32
 8693     }
 8694 $add-operation-and-inputs-to-stmt:end:
 8695     # . reclaim locals
 8696     81 0/subop/add %esp 0x10/imm32
 8697     # . restore registers
 8698     5f/pop-to-edi
 8699     5e/pop-to-esi
 8700     5b/pop-to-ebx
 8701     5a/pop-to-edx
 8702     59/pop-to-ecx
 8703     58/pop-to-eax
 8704     # . epilogue
 8705     89/<- %esp 5/r32/ebp
 8706     5d/pop-to-ebp
 8707     c3/return
 8708 
 8709 $add-operation-and-inputs-to-stmt:abort:
 8710     # error("fn ___: invalid identifier in '" line "'\n")
 8711     (write-buffered *(ebp+0x18) "fn ")
 8712     8b/-> *(ebp+0x14) 0/r32/eax
 8713     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8714     (write-buffered *(ebp+0x18) %eax)
 8715     (rewind-stream *(ebp+0xc))
 8716     (write-buffered *(ebp+0x18) ": invalid identifier in '")
 8717     (write-stream-data *(ebp+0x18) *(ebp+0xc))
 8718     (write-buffered *(ebp+0x18) "'\n")
 8719     (flush *(ebp+0x18))
 8720     (stop *(ebp+0x1c) 1)
 8721     # never gets here
 8722 
 8723 stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
 8724     # . prologue
 8725     55/push-ebp
 8726     89/<- %ebp 4/r32/esp
 8727     # . save registers
 8728     51/push-ecx
 8729     # var word-slice/ecx: slice
 8730     68/push 0/imm32/end
 8731     68/push 0/imm32/start
 8732     89/<- %ecx 4/r32/esp
 8733     # result = false
 8734     b8/copy-to-eax 0/imm32/false
 8735     (rewind-stream *(ebp+8))
 8736     {
 8737       (next-mu-token *(ebp+8) %ecx)
 8738       # if slice-empty?(word-slice) break
 8739       (slice-empty? %ecx)
 8740       3d/compare-eax-and 0/imm32/false
 8741       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 8742       0f 85/jump-if-!= break/disp32
 8743       # if slice-starts-with?(word-slice, '#') break
 8744       # . eax = *word-slice->start
 8745       8b/-> *ecx 0/r32/eax
 8746       8a/copy-byte *eax 0/r32/AL
 8747       81 4/subop/and %eax 0xff/imm32
 8748       # . if (eax == '#') break
 8749       3d/compare-eax-and 0x23/imm32/hash
 8750       b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
 8751       0f 84/jump-if-= break/disp32
 8752       # if slice-equal?(word-slice, '<-') return true
 8753       (slice-equal? %ecx "<-")
 8754       3d/compare-eax-and 0/imm32/false
 8755       74/jump-if-= loop/disp8
 8756       b8/copy-to-eax 1/imm32/true
 8757     }
 8758 $stmt-has-outputs:end:
 8759     (rewind-stream *(ebp+8))
 8760     # . reclaim locals
 8761     81 0/subop/add %esp 8/imm32
 8762     # . restore registers
 8763     59/pop-to-ecx
 8764     # . epilogue
 8765     89/<- %esp 5/r32/ebp
 8766     5d/pop-to-ebp
 8767     c3/return
 8768 
 8769 # if 'name' starts with a digit, create a new literal var for it
 8770 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found
 8771 lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8772     # . prologue
 8773     55/push-ebp
 8774     89/<- %ebp 4/r32/esp
 8775     # . save registers
 8776     50/push-eax
 8777     51/push-ecx
 8778     56/push-esi
 8779     # esi = name
 8780     8b/-> *(ebp+8) 6/r32/esi
 8781     # if slice-empty?(name) abort
 8782     (slice-empty? %esi)  # => eax
 8783     3d/compare-eax-and 0/imm32/false
 8784     0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
 8785     # var c/ecx: byte = *name->start
 8786     8b/-> *esi 1/r32/ecx
 8787     8a/copy-byte *ecx 1/r32/CL
 8788     81 4/subop/and %ecx 0xff/imm32
 8789     # if is-decimal-digit?(c) return new var(name)
 8790     {
 8791       (is-decimal-digit? %ecx)  # => eax
 8792       3d/compare-eax-and 0/imm32/false
 8793       74/jump-if-= break/disp8
 8794 $lookup-var-or-literal:literal:
 8795       (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
 8796       eb/jump $lookup-var-or-literal:end/disp8
 8797     }
 8798     # else if (c == '"') return new var(name)
 8799     {
 8800       81 7/subop/compare %ecx 0x22/imm32/dquote
 8801       75/jump-if-!= break/disp8
 8802 $lookup-var-or-literal:literal-string:
 8803       (new-literal Heap %esi *(ebp+0x10))
 8804       eb/jump $lookup-var-or-literal:end/disp8
 8805     }
 8806     # otherwise return lookup-var(name, vars)
 8807     {
 8808 $lookup-var-or-literal:var:
 8809       (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8810     }
 8811 $lookup-var-or-literal:end:
 8812     # . restore registers
 8813     5e/pop-to-esi
 8814     59/pop-to-ecx
 8815     58/pop-to-eax
 8816     # . epilogue
 8817     89/<- %esp 5/r32/ebp
 8818     5d/pop-to-ebp
 8819     c3/return
 8820 
 8821 $lookup-var-or-literal:abort:
 8822     (write-buffered *(ebp+0x18) "fn ")
 8823     8b/-> *(ebp+0x14) 0/r32/eax
 8824     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8825     (write-buffered *(ebp+0x18) %eax)
 8826     (write-buffered *(ebp+0x18) ": empty variable!")
 8827     (flush *(ebp+0x18))
 8828     (stop *(ebp+0x1c) 1)
 8829     # never gets here
 8830 
 8831 # return first 'name' from the top (back) of 'vars' and abort if not found
 8832 lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8833     # . prologue
 8834     55/push-ebp
 8835     89/<- %ebp 4/r32/esp
 8836     # . save registers
 8837     50/push-eax
 8838     #
 8839     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
 8840     # if (*out == 0) abort
 8841     8b/-> *(ebp+0x10) 0/r32/eax
 8842     81 7/subop/compare *eax 0/imm32
 8843     74/jump-if-= $lookup-var:abort/disp8
 8844 $lookup-var:end:
 8845     # . restore registers
 8846     58/pop-to-eax
 8847     # . epilogue
 8848     89/<- %esp 5/r32/ebp
 8849     5d/pop-to-ebp
 8850     c3/return
 8851 
 8852 $lookup-var:abort:
 8853     (write-buffered *(ebp+0x18) "fn ")
 8854     8b/-> *(ebp+0x14) 0/r32/eax
 8855     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8856     (write-buffered *(ebp+0x18) %eax)
 8857     (write-buffered *(ebp+0x18) ": unknown variable '")
 8858     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8859     (write-buffered *(ebp+0x18) "'\n")
 8860     (flush *(ebp+0x18))
 8861     (stop *(ebp+0x1c) 1)
 8862     # never gets here
 8863 
 8864 # return first 'name' from the top (back) of 'vars', and 0/null if not found
 8865 # ensure that 'name' if in a register is the topmost variable in that register
 8866 lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 8867     # pseudocode:
 8868     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 8869     #   var min = vars->data
 8870     #   while curr >= min
 8871     #     var v: (handle var) = *curr
 8872     #     if v->name == name
 8873     #       return
 8874     #     curr -= 12
 8875     #
 8876     # . prologue
 8877     55/push-ebp
 8878     89/<- %ebp 4/r32/esp
 8879     # . save registers
 8880     50/push-eax
 8881     51/push-ecx
 8882     52/push-edx
 8883     53/push-ebx
 8884     56/push-esi
 8885     57/push-edi
 8886     # clear out
 8887     (zero-out *(ebp+0x10) *Handle-size)
 8888     # esi = vars
 8889     8b/-> *(ebp+0xc) 6/r32/esi
 8890     # ebx = vars->top
 8891     8b/-> *esi 3/r32/ebx
 8892     # if (vars->top > vars->size) abort
 8893     3b/compare<- *(esi+4) 0/r32/eax
 8894     0f 8f/jump-if-> $lookup-var-helper:error1/disp32
 8895     # var min/edx: (addr handle var) = vars->data
 8896     8d/copy-address *(esi+8) 2/r32/edx
 8897     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 8898     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 8899     # var var-in-reg/edi: 8 addrs
 8900     68/push 0/imm32
 8901     68/push 0/imm32
 8902     68/push 0/imm32
 8903     68/push 0/imm32
 8904     68/push 0/imm32
 8905     68/push 0/imm32
 8906     68/push 0/imm32
 8907     68/push 0/imm32
 8908     89/<- %edi 4/r32/esp
 8909     {
 8910 $lookup-var-helper:loop:
 8911       # if (curr < min) return
 8912       39/compare %ebx 2/r32/edx
 8913       0f 82/jump-if-addr< break/disp32
 8914       # var v/ecx: (addr var) = lookup(*curr)
 8915       (lookup *ebx *(ebx+4))  # => eax
 8916       89/<- %ecx 0/r32/eax
 8917       # var vn/eax: (addr array byte) = lookup(v->name)
 8918       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
 8919       # if (vn == name) return curr
 8920       (slice-equal? *(ebp+8) %eax)  # => eax
 8921       3d/compare-eax-and 0/imm32/false
 8922       {
 8923         74/jump-if-= break/disp8
 8924 $lookup-var-helper:found:
 8925         # var vr/eax: (addr array byte) = lookup(v->register)
 8926         (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8927         3d/compare-eax-and 0/imm32
 8928         {
 8929           74/jump-if-= break/disp8
 8930 $lookup-var-helper:found-register:
 8931           # var reg/eax: int = get(Registers, vr)
 8932           (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 8933           8b/-> *eax 0/r32/eax
 8934           # if (var-in-reg[reg]) error
 8935           8b/-> *(edi+eax<<2) 0/r32/eax
 8936           3d/compare-eax-and 0/imm32
 8937           0f 85/jump-if-!= $lookup-var-helper:error2/disp32
 8938         }
 8939 $lookup-var-helper:return:
 8940         # esi = out
 8941         8b/-> *(ebp+0x10) 6/r32/esi
 8942         # *out = *curr
 8943         8b/-> *ebx 0/r32/eax
 8944         89/<- *esi 0/r32/eax
 8945         8b/-> *(ebx+4) 0/r32/eax
 8946         89/<- *(esi+4) 0/r32/eax
 8947         # return
 8948         eb/jump $lookup-var-helper:end/disp8
 8949       }
 8950       # 'name' not yet found; update var-in-reg if v in register
 8951       # . var vr/eax: (addr array byte) = lookup(v->register)
 8952       (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
 8953       # . if (var == 0) continue
 8954       3d/compare-eax-and 0/imm32
 8955       74/jump-if-= $lookup-var-helper:continue/disp8
 8956       # . var reg/eax: int = get(Registers, vr)
 8957       (get Mu-registers %eax 0xc "Mu-registers")  # => eax
 8958       8b/-> *eax 0/r32/eax
 8959       # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
 8960       81 7/subop/compare *(edi+eax<<2) 0/imm32
 8961       75/jump-if-!= $lookup-var-helper:continue/disp8
 8962       89/<- *(edi+eax<<2) 1/r32/ecx
 8963 $lookup-var-helper:continue:
 8964       # curr -= 12
 8965       81 5/subop/subtract %ebx 0xc/imm32
 8966       e9/jump loop/disp32
 8967     }
 8968 $lookup-var-helper:end:
 8969     # . reclaim locals
 8970     81 0/subop/add %esp 0x20/imm32
 8971     # . restore registers
 8972     5f/pop-to-edi
 8973     5e/pop-to-esi
 8974     5b/pop-to-ebx
 8975     5a/pop-to-edx
 8976     59/pop-to-ecx
 8977     58/pop-to-eax
 8978     # . epilogue
 8979     89/<- %esp 5/r32/ebp
 8980     5d/pop-to-ebp
 8981     c3/return
 8982 
 8983 $lookup-var-helper:error1:
 8984     (write-buffered *(ebp+0x18) "fn ")
 8985     8b/-> *(ebp+0x14) 0/r32/eax
 8986     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 8987     (write-buffered *(ebp+0x18) %eax)
 8988     (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
 8989     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 8990     (write-buffered *(ebp+0x18) "'\n")
 8991     (flush *(ebp+0x18))
 8992     (stop *(ebp+0x1c) 1)
 8993     # never gets here
 8994 
 8995 $lookup-var-helper:error2:
 8996     # eax contains the conflicting var at this point
 8997     (write-buffered *(ebp+0x18) "fn ")
 8998     50/push-eax
 8999     8b/-> *(ebp+0x14) 0/r32/eax
 9000     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9001     (write-buffered *(ebp+0x18) %eax)
 9002     58/pop-eax
 9003     (write-buffered *(ebp+0x18) ": register ")
 9004     50/push-eax
 9005     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
 9006     (write-buffered *(ebp+0x18) %eax)
 9007     58/pop-to-eax
 9008     (write-buffered *(ebp+0x18) " reads var '")
 9009     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9010     (write-buffered *(ebp+0x18) "' after writing var '")
 9011     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9012     (write-buffered *(ebp+0x18) %eax)
 9013     (write-buffered *(ebp+0x18) "'\n")
 9014     (flush *(ebp+0x18))
 9015     (stop *(ebp+0x1c) 1)
 9016     # never gets here
 9017 
 9018 dump-vars:  # vars: (addr stack live-var)
 9019     # pseudocode:
 9020     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9021     #   var min = vars->data
 9022     #   while curr >= min
 9023     #     var v: (handle var) = *curr
 9024     #     print v
 9025     #     curr -= 12
 9026     #
 9027     # . prologue
 9028     55/push-ebp
 9029     89/<- %ebp 4/r32/esp
 9030     # . save registers
 9031     52/push-edx
 9032     53/push-ebx
 9033     56/push-esi
 9034     # esi = vars
 9035     8b/-> *(ebp+8) 6/r32/esi
 9036     # ebx = vars->top
 9037     8b/-> *esi 3/r32/ebx
 9038     # var min/edx: (addr handle var) = vars->data
 9039     8d/copy-address *(esi+8) 2/r32/edx
 9040     # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
 9041     8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
 9042     {
 9043 $dump-vars:loop:
 9044       # if (curr < min) return
 9045       39/compare %ebx 2/r32/edx
 9046       0f 82/jump-if-addr< break/disp32
 9047       #
 9048       (write-buffered Stderr "  var@")
 9049       (dump-var 2 %ebx)
 9050       # curr -= 12
 9051       81 5/subop/subtract %ebx 0xc/imm32
 9052       e9/jump loop/disp32
 9053     }
 9054 $dump-vars:end:
 9055     # . restore registers
 9056     5e/pop-to-esi
 9057     5b/pop-to-ebx
 9058     5a/pop-to-edx
 9059     # . epilogue
 9060     89/<- %esp 5/r32/ebp
 9061     5d/pop-to-ebp
 9062     c3/return
 9063 
 9064 == data
 9065 # Like Registers, but no esp or ebp
 9066 Mu-registers:  # (addr stream {(handle array byte), int})
 9067   # a table is a stream
 9068   0x48/imm32/write
 9069   0/imm32/read
 9070   0x48/imm32/length
 9071   # data
 9072   # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
 9073   0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
 9074   0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
 9075   0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
 9076   0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
 9077   0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
 9078   0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32
 9079 
 9080 $Mu-register-eax:
 9081   0x11/imm32/alloc-id
 9082   3/imm32/size
 9083   0x65/e 0x61/a 0x78/x
 9084 
 9085 $Mu-register-ecx:
 9086   0x11/imm32/alloc-id
 9087   3/imm32/size
 9088   0x65/e 0x63/c 0x78/x
 9089 
 9090 $Mu-register-edx:
 9091   0x11/imm32/alloc-id
 9092   3/imm32/size
 9093   0x65/e 0x64/d 0x78/x
 9094 
 9095 $Mu-register-ebx:
 9096   0x11/imm32/alloc-id
 9097   3/imm32/size
 9098   0x65/e 0x62/b 0x78/x
 9099 
 9100 $Mu-register-esi:
 9101   0x11/imm32/alloc-id
 9102   3/imm32/size
 9103   0x65/e 0x73/s 0x69/i
 9104 
 9105 $Mu-register-edi:
 9106   0x11/imm32/alloc-id
 9107   3/imm32/size
 9108   0x65/e 0x64/d 0x69/i
 9109 
 9110 == code
 9111 
 9112 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
 9113 lookup-var-or-find-in-fn-outputs:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
 9114     # . prologue
 9115     55/push-ebp
 9116     89/<- %ebp 4/r32/esp
 9117     # . save registers
 9118     50/push-eax
 9119     #
 9120     (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
 9121     {
 9122       # if (out != 0) return
 9123       8b/-> *(ebp+0x14) 0/r32/eax
 9124       81 7/subop/compare *eax 0/imm32
 9125       75/jump-if-!= break/disp8
 9126       # if name is one of fn's outputs, return it
 9127       (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
 9128       8b/-> *(ebp+0x14) 0/r32/eax
 9129       81 7/subop/compare *eax 0/imm32
 9130       # otherwise abort
 9131       0f 84/jump-if-= $lookup-or-define-var:abort/disp32
 9132     }
 9133 $lookup-or-define-var:end:
 9134     # . restore registers
 9135     58/pop-to-eax
 9136     # . epilogue
 9137     89/<- %esp 5/r32/ebp
 9138     5d/pop-to-ebp
 9139     c3/return
 9140 
 9141 $lookup-or-define-var:abort:
 9142     (write-buffered *(ebp+0x18) "unknown variable '")
 9143     (write-slice-buffered *(ebp+0x18) *(ebp+8))
 9144     (write-buffered *(ebp+0x18) "'\n")
 9145     (flush *(ebp+0x18))
 9146     (stop *(ebp+0x1c) 1)
 9147     # never gets here
 9148 
 9149 find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
 9150     # . prologue
 9151     55/push-ebp
 9152     89/<- %ebp 4/r32/esp
 9153     # . save registers
 9154     50/push-eax
 9155     51/push-ecx
 9156     # var curr/ecx: (addr list var) = lookup(fn->outputs)
 9157     8b/-> *(ebp+8) 1/r32/ecx
 9158     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
 9159     89/<- %ecx 0/r32/eax
 9160     # while curr != null
 9161     {
 9162       81 7/subop/compare %ecx 0/imm32
 9163       74/jump-if-= break/disp8
 9164       # var v/eax: (addr var) = lookup(curr->value)
 9165       (lookup *ecx *(ecx+4))  # List-value List-value => eax
 9166       # var s/eax: (addr array byte) = lookup(v->name)
 9167       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9168       # if (s == name) return curr->value
 9169       (slice-equal? *(ebp+0xc) %eax)  # => eax
 9170       3d/compare-eax-and 0/imm32/false
 9171       {
 9172         74/jump-if-= break/disp8
 9173         # var edi = out
 9174         57/push-edi
 9175         8b/-> *(ebp+0x10) 7/r32/edi
 9176         # *out = curr->value
 9177         8b/-> *ecx 0/r32/eax
 9178         89/<- *edi 0/r32/eax
 9179         8b/-> *(ecx+4) 0/r32/eax
 9180         89/<- *(edi+4) 0/r32/eax
 9181         #
 9182         5f/pop-to-edi
 9183         eb/jump $find-in-function-outputs:end/disp8
 9184       }
 9185       # curr = curr->next
 9186       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
 9187       89/<- %ecx 0/r32/eax
 9188       #
 9189       eb/jump loop/disp8
 9190     }
 9191     b8/copy-to-eax 0/imm32
 9192 $find-in-function-outputs:end:
 9193     # . restore registers
 9194     59/pop-to-ecx
 9195     58/pop-to-eax
 9196     # . epilogue
 9197     89/<- %esp 5/r32/ebp
 9198     5d/pop-to-ebp
 9199     c3/return
 9200 
 9201 # push 'out' to 'vars' if not already there; it's assumed to be a fn output
 9202 maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
 9203     # . prologue
 9204     55/push-ebp
 9205     89/<- %ebp 4/r32/esp
 9206     # . save registers
 9207     50/push-eax
 9208     # var out-addr/eax: (addr var)
 9209     (lookup *(ebp+8) *(ebp+0xc))  # => eax
 9210     #
 9211     (binding-exists? %eax *(ebp+0x10))  # => eax
 9212     3d/compare-eax-and 0/imm32/false
 9213     75/jump-if-!= $maybe-define-var:end/disp8
 9214     # otherwise update vars
 9215     (push *(ebp+0x10) *(ebp+8))
 9216     (push *(ebp+0x10) *(ebp+0xc))
 9217     (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
 9218 $maybe-define-var:end:
 9219     # . restore registers
 9220     58/pop-to-eax
 9221     # . epilogue
 9222     89/<- %esp 5/r32/ebp
 9223     5d/pop-to-ebp
 9224     c3/return
 9225 
 9226 # simpler version of lookup-var-helper
 9227 binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
 9228     # pseudocode:
 9229     #   var curr: (addr handle var) = &vars->data[vars->top - 12]
 9230     #   var min = vars->data
 9231     #   while curr >= min
 9232     #     var v: (handle var) = *curr
 9233     #     if v->name == target->name
 9234     #       return true
 9235     #     curr -= 12
 9236     #   return false
 9237     #
 9238     # . prologue
 9239     55/push-ebp
 9240     89/<- %ebp 4/r32/esp
 9241     # . save registers
 9242     51/push-ecx
 9243     52/push-edx
 9244     56/push-esi
 9245     # var target-name/ecx: (addr array byte) = lookup(target->name)
 9246     8b/-> *(ebp+8) 0/r32/eax
 9247     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9248     89/<- %ecx 0/r32/eax
 9249     # esi = vars
 9250     8b/-> *(ebp+0xc) 6/r32/esi
 9251     # eax = vars->top
 9252     8b/-> *esi 0/r32/eax
 9253     # var min/edx: (addr handle var) = vars->data
 9254     8d/copy-address *(esi+8) 2/r32/edx
 9255     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
 9256     8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
 9257     {
 9258 $binding-exists?:loop:
 9259       # if (curr < min) return
 9260       39/compare %esi 2/r32/edx
 9261       0f 82/jump-if-addr< break/disp32
 9262       # var v/eax: (addr var) = lookup(*curr)
 9263       (lookup *esi *(esi+4))  # => eax
 9264       # var vn/eax: (addr array byte) = lookup(v->name)
 9265       (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9266       # if (vn == target-name) return true
 9267       (string-equal? %ecx %eax)  # => eax
 9268       3d/compare-eax-and 0/imm32/false
 9269       75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
 9270       # curr -= 12
 9271       81 5/subop/subtract %esi 0xc/imm32
 9272       e9/jump loop/disp32
 9273     }
 9274     b8/copy-to-eax 0/imm32/false
 9275 $binding-exists?:end:
 9276     # . restore registers
 9277     5e/pop-to-esi
 9278     5a/pop-to-edx
 9279     59/pop-to-ecx
 9280     # . epilogue
 9281     89/<- %esp 5/r32/ebp
 9282     5d/pop-to-ebp
 9283     c3/return
 9284 
 9285 test-parse-mu-stmt:
 9286     # . prologue
 9287     55/push-ebp
 9288     89/<- %ebp 4/r32/esp
 9289     # setup
 9290     (clear-stream _test-input-stream)
 9291     (write _test-input-stream "increment n\n")
 9292     # var vars/ecx: (stack (addr var) 16)
 9293     81 5/subop/subtract %esp 0xc0/imm32
 9294     68/push 0xc0/imm32/size
 9295     68/push 0/imm32/top
 9296     89/<- %ecx 4/r32/esp
 9297     (clear-stack %ecx)
 9298     # var v/edx: (handle var)
 9299     68/push 0/imm32
 9300     68/push 0/imm32
 9301     89/<- %edx 4/r32/esp
 9302     # var s/eax: (handle array byte)
 9303     68/push 0/imm32
 9304     68/push 0/imm32
 9305     89/<- %eax 4/r32/esp
 9306     # v = new var("n")
 9307     (copy-array Heap "n" %eax)
 9308     (new-var Heap *eax *(eax+4) %edx)
 9309     #
 9310     (push %ecx *edx)
 9311     (push %ecx *(edx+4))
 9312     (push %ecx 0)
 9313     # var out/eax: (handle stmt)
 9314     68/push 0/imm32
 9315     68/push 0/imm32
 9316     89/<- %eax 4/r32/esp
 9317     # convert
 9318     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9319     # var out-addr/edx: (addr stmt) = lookup(*out)
 9320     (lookup *eax *(eax+4))  # => eax
 9321     89/<- %edx 0/r32/eax
 9322     # out->tag
 9323     (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
 9324     # out->operation
 9325     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9326     (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
 9327     # out->inouts->value->name
 9328     # . eax = out->inouts
 9329     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9330     # . eax = out->inouts->value
 9331     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9332     # . eax = out->inouts->value->name
 9333     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9334     # .
 9335     (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
 9336     # . epilogue
 9337     89/<- %esp 5/r32/ebp
 9338     5d/pop-to-ebp
 9339     c3/return
 9340 
 9341 test-parse-mu-stmt-with-comma:
 9342     # . prologue
 9343     55/push-ebp
 9344     89/<- %ebp 4/r32/esp
 9345     # setup
 9346     (clear-stream _test-input-stream)
 9347     (write _test-input-stream "copy-to n, 3\n")
 9348     # var vars/ecx: (stack (addr var) 16)
 9349     81 5/subop/subtract %esp 0xc0/imm32
 9350     68/push 0xc0/imm32/size
 9351     68/push 0/imm32/top
 9352     89/<- %ecx 4/r32/esp
 9353     (clear-stack %ecx)
 9354     # var v/edx: (handle var)
 9355     68/push 0/imm32
 9356     68/push 0/imm32
 9357     89/<- %edx 4/r32/esp
 9358     # var s/eax: (handle array byte)
 9359     68/push 0/imm32
 9360     68/push 0/imm32
 9361     89/<- %eax 4/r32/esp
 9362     # v = new var("n")
 9363     (copy-array Heap "n" %eax)
 9364     (new-var Heap *eax *(eax+4) %edx)
 9365     #
 9366     (push %ecx *edx)
 9367     (push %ecx *(edx+4))
 9368     (push %ecx 0)
 9369     # var out/eax: (handle stmt)
 9370     68/push 0/imm32
 9371     68/push 0/imm32
 9372     89/<- %eax 4/r32/esp
 9373     # convert
 9374     (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
 9375     # var out-addr/edx: (addr stmt) = lookup(*out)
 9376     (lookup *eax *(eax+4))  # => eax
 9377     89/<- %edx 0/r32/eax
 9378     # out->tag
 9379     (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
 9380     # out->operation
 9381     (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
 9382     (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
 9383     # out->inouts->value->name
 9384     # . eax = out->inouts
 9385     (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
 9386     # . eax = out->inouts->value
 9387     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9388     # . eax = out->inouts->value->name
 9389     (lookup *eax *(eax+4))  # Var-name Var-name => eax
 9390     # .
 9391     (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
 9392     # . epilogue
 9393     89/<- %esp 5/r32/ebp
 9394     5d/pop-to-ebp
 9395     c3/return
 9396 
 9397 new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
 9398     # . prologue
 9399     55/push-ebp
 9400     89/<- %ebp 4/r32/esp
 9401     # . save registers
 9402     50/push-eax
 9403     51/push-ecx
 9404     # ecx = out
 9405     8b/-> *(ebp+0x14) 1/r32/ecx
 9406     #
 9407     (allocate *(ebp+8) *Var-size %ecx)
 9408     # var out-addr/eax: (addr var)
 9409     (lookup *ecx *(ecx+4))  # => eax
 9410     # out-addr->name = name
 9411     8b/-> *(ebp+0xc) 1/r32/ecx
 9412     89/<- *eax 1/r32/ecx  # Var-name
 9413     8b/-> *(ebp+0x10) 1/r32/ecx
 9414     89/<- *(eax+4) 1/r32/ecx  # Var-name
 9415 #?     (write-buffered Stderr "var ")
 9416 #?     (lookup *(ebp+0xc) *(ebp+0x10))
 9417 #?     (write-buffered Stderr %eax)
 9418 #?     (write-buffered Stderr " at ")
 9419 #?     8b/-> *(ebp+0x14) 1/r32/ecx
 9420 #?     (lookup *ecx *(ecx+4))  # => eax
 9421 #?     (write-int32-hex-buffered Stderr %eax)
 9422 #?     (write-buffered Stderr Newline)
 9423 #?     (flush Stderr)
 9424 $new-var:end:
 9425     # . restore registers
 9426     59/pop-to-ecx
 9427     58/pop-to-eax
 9428     # . epilogue
 9429     89/<- %esp 5/r32/ebp
 9430     5d/pop-to-ebp
 9431     c3/return
 9432 
 9433 new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
 9434     # . prologue
 9435     55/push-ebp
 9436     89/<- %ebp 4/r32/esp
 9437     # . save registers
 9438     50/push-eax
 9439     51/push-ecx
 9440     # if (!is-hex-int?(name)) abort
 9441     (is-hex-int? *(ebp+0xc))  # => eax
 9442     3d/compare-eax-and 0/imm32/false
 9443     0f 84/jump-if-= $new-literal-integer:abort/disp32
 9444     # out = new var(s)
 9445     (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 9446     # var out-addr/ecx: (addr var) = lookup(*out)
 9447     8b/-> *(ebp+0x10) 0/r32/eax
 9448     (lookup *eax *(eax+4))  # => eax
 9449     89/<- %ecx 0/r32/eax
 9450     # out-addr->block-depth = *Curr-block-depth
 9451     8b/-> *Curr-block-depth 0/r32/eax
 9452     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9453     # out-addr->type = new tree()
 9454     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 9455     (allocate *(ebp+8) *Type-tree-size %eax)
 9456     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9457     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
 9458     # nothing else to do; default type is 'literal'
 9459 $new-literal-integer:end:
 9460     # . reclaim locals
 9461     81 0/subop/add %esp 8/imm32
 9462     # . restore registers
 9463     59/pop-to-ecx
 9464     58/pop-to-eax
 9465     # . epilogue
 9466     89/<- %esp 5/r32/ebp
 9467     5d/pop-to-ebp
 9468     c3/return
 9469 
 9470 $new-literal-integer:abort:
 9471     (write-buffered *(ebp+0x18) "fn ")
 9472     8b/-> *(ebp+0x14) 0/r32/eax
 9473     (lookup *eax *(eax+4))  # Function-name Function-name => eax
 9474     (write-buffered *(ebp+0x18) %eax)
 9475     (write-buffered *(ebp+0x18) ": variable cannot begin with a digit '")
 9476     (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
 9477     (write-buffered *(ebp+0x18) "'\n")
 9478     (flush *(ebp+0x18))
 9479     (stop *(ebp+0x1c) 1)
 9480     # never gets here
 9481 
 9482 new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 9483     # . prologue
 9484     55/push-ebp
 9485     89/<- %ebp 4/r32/esp
 9486     # . save registers
 9487     50/push-eax
 9488     51/push-ecx
 9489     # var s/ecx: (handle array byte)
 9490     68/push 0/imm32
 9491     68/push 0/imm32
 9492     89/<- %ecx 4/r32/esp
 9493     # s = slice-to-string(name)
 9494     (slice-to-string Heap *(ebp+0xc) %ecx)
 9495     # allocate to out
 9496     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 9497     # var out-addr/ecx: (addr var) = lookup(*out)
 9498     8b/-> *(ebp+0x10) 1/r32/ecx
 9499     (lookup *ecx *(ecx+4))  # => eax
 9500     89/<- %ecx 0/r32/eax
 9501     # out-addr->block-depth = *Curr-block-depth
 9502     8b/-> *Curr-block-depth 0/r32/eax
 9503     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
 9504     # out-addr->type/eax = new type
 9505     8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
 9506     (allocate *(ebp+8) *Type-tree-size %eax)
 9507     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
 9508     # nothing else to do; default type is 'literal'
 9509     c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
 9510 $new-literal:end:
 9511     # . reclaim locals
 9512     81 0/subop/add %esp 8/imm32
 9513     # . restore registers
 9514     59/pop-to-ecx
 9515     58/pop-to-eax
 9516     # . epilogue
 9517     89/<- %esp 5/r32/ebp
 9518     5d/pop-to-ebp
 9519     c3/return
 9520 
 9521 new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
 9522     # . prologue
 9523     55/push-ebp
 9524     89/<- %ebp 4/r32/esp
 9525     # . save registers
 9526     51/push-ecx
 9527     # var tmp/ecx: (handle array byte)
 9528     68/push 0/imm32
 9529     68/push 0/imm32
 9530     89/<- %ecx 4/r32/esp
 9531     # tmp = slice-to-string(name)
 9532     (slice-to-string Heap *(ebp+0xc) %ecx)
 9533     # out = new-var(tmp)
 9534     (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
 9535 $new-var-from-slice:end:
 9536     # . reclaim locals
 9537     81 0/subop/add %esp 8/imm32
 9538     # . restore registers
 9539     59/pop-to-ecx
 9540     # . epilogue
 9541     89/<- %esp 5/r32/ebp
 9542     5d/pop-to-ebp
 9543     c3/return
 9544 
 9545 new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 9546     # . prologue
 9547     55/push-ebp
 9548     89/<- %ebp 4/r32/esp
 9549     # . save registers
 9550     50/push-eax
 9551     51/push-ecx
 9552     #
 9553     (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
 9554     # var out-addr/eax: (addr stmt) = lookup(*out)
 9555     8b/-> *(ebp+0x14) 0/r32/eax
 9556     (lookup *eax *(eax+4))  # => eax
 9557     # out-addr->tag = stmt
 9558     c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
 9559     # result->var = var
 9560     8b/-> *(ebp+0xc) 1/r32/ecx
 9561     89/<- *(eax+4) 1/r32/ecx  # Vardef-var
 9562     8b/-> *(ebp+0x10) 1/r32/ecx
 9563     89/<- *(eax+8) 1/r32/ecx  # Vardef-var
 9564 $new-var-def:end:
 9565     # . restore registers
 9566     59/pop-to-ecx
 9567     58/pop-to-eax
 9568     # . epilogue
 9569     89/<- %esp 5/r32/ebp
 9570     5d/pop-to-ebp
 9571     c3/return
 9572 
 9573 new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
 9574     # . prologue
 9575     55/push-ebp
 9576     89/<- %ebp 4/r32/esp
 9577     # . save registers
 9578     50/push-eax
 9579     # eax = out
 9580     8b/-> *(ebp+0x14) 0/r32/eax
 9581     #
 9582     (allocate *(ebp+8) *Stmt-size %eax)
 9583     # var out-addr/eax: (addr stmt) = lookup(*out)
 9584     (lookup *eax *(eax+4))  # => eax
 9585     # set tag
 9586     c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
 9587     # set output
 9588     8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
 9589     (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
 9590 $new-reg-var-def:end:
 9591     # . restore registers
 9592     58/pop-to-eax
 9593     # . epilogue
 9594     89/<- %esp 5/r32/ebp
 9595     5d/pop-to-ebp
 9596     c3/return
 9597 
 9598 append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
 9599     # . prologue
 9600     55/push-ebp
 9601     89/<- %ebp 4/r32/esp
 9602     # . save registers
 9603     50/push-eax
 9604     51/push-ecx
 9605     57/push-edi
 9606     # edi = out
 9607     8b/-> *(ebp+0x1c) 7/r32/edi
 9608     # *out = new list
 9609     (allocate *(ebp+8) *List-size %edi)
 9610     # var out-addr/edi: (addr list _type) = lookup(*out)
 9611     (lookup *edi *(edi+4))  # => eax
 9612     89/<- %edi 0/r32/eax
 9613     # out-addr->value = value
 9614     8b/-> *(ebp+0xc) 0/r32/eax
 9615     89/<- *edi 0/r32/eax  # List-value
 9616     8b/-> *(ebp+0x10) 0/r32/eax
 9617     89/<- *(edi+4) 0/r32/eax  # List-value
 9618     # if (list == null) return
 9619     81 7/subop/compare *(ebp+0x14) 0/imm32
 9620     74/jump-if-= $append-list:end/disp8
 9621     # otherwise append
 9622 $append-list:non-empty-list:
 9623     # var curr/eax: (addr list _type) = lookup(list)
 9624     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 9625     # while (curr->next != null) curr = curr->next
 9626     {
 9627       81 7/subop/compare *(eax+8) 0/imm32  # List-next
 9628       74/jump-if-= break/disp8
 9629       # curr = lookup(curr->next)
 9630       (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
 9631       #
 9632       eb/jump loop/disp8
 9633     }
 9634     # edi = out
 9635     8b/-> *(ebp+0x1c) 7/r32/edi
 9636     # curr->next = out
 9637     8b/-> *edi 1/r32/ecx
 9638     89/<- *(eax+8) 1/r32/ecx  # List-next
 9639     8b/-> *(edi+4) 1/r32/ecx
 9640     89/<- *(eax+0xc) 1/r32/ecx  # List-next
 9641     # out = list
 9642     8b/-> *(ebp+0x14) 1/r32/ecx
 9643     89/<- *edi 1/r32/ecx
 9644     8b/-> *(ebp+0x18) 1/r32/ecx
 9645     89/<- *(edi+4) 1/r32/ecx
 9646 $append-list:end:
 9647     # . restore registers
 9648     5f/pop-to-edi
 9649     59/pop-to-ecx
 9650     58/pop-to-eax
 9651     # . epilogue
 9652     89/<- %esp 5/r32/ebp
 9653     5d/pop-to-ebp
 9654     c3/return
 9655 
 9656 append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
 9657     # . prologue
 9658     55/push-ebp
 9659     89/<- %ebp 4/r32/esp
 9660     # . save registers
 9661     50/push-eax
 9662     51/push-ecx
 9663     57/push-edi
 9664     # edi = out
 9665     8b/-> *(ebp+0x20) 7/r32/edi
 9666     # out = new stmt-var
 9667     (allocate *(ebp+8) *Stmt-var-size %edi)
 9668     # var out-addr/ecx: (addr stmt-var) = lookup(*out)
 9669     (lookup *edi *(edi+4))  # => eax
 9670     89/<- %ecx 0/r32/eax
 9671     # out-addr->value = v
 9672     8b/-> *(ebp+0xc) 0/r32/eax
 9673     89/<- *ecx 0/r32/eax  # Stmt-var-value
 9674     8b/-> *(ebp+0x10) 0/r32/eax
 9675     89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
 9676     # out-addr->is-deref? = is-deref?
 9677     8b/-> *(ebp+0x1c) 0/r32/eax
 9678     89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
 9679     # if (vars == null) return result
 9680     81 7/subop/compare *(ebp+0x14) 0/imm32/null
 9681     74/jump-if-= $append-stmt-var:end/disp8
 9682     # otherwise append
 9683     # var curr/eax: (addr stmt-var) = lookup(vars)
 9684     (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
 9685     # while (curr->next != null) curr = curr->next
 9686     {
 9687       81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
 9688       74/jump-if-= break/disp8
 9689       # curr = lookup(curr->next)
 9690       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
 9691       #
 9692       eb/jump loop/disp8
 9693     }
 9694     # curr->next = out
 9695     8b/-> *edi 1/r32/ecx
 9696     89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
 9697     8b/-> *(edi+4) 1/r32/ecx
 9698     89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
 9699     # out = vars
 9700     8b/-> *(ebp+0x14) 1/r32/ecx
 9701     89/<- *edi 1/r32/ecx
 9702     8b/-> *(ebp+0x18) 1/r32/ecx
 9703     89/<- *(edi+4) 1/r32/ecx
 9704 $append-stmt-var:end:
 9705     # . restore registers
 9706     5f/pop-to-edi
 9707     59/pop-to-ecx
 9708     58/pop-to-eax
 9709     # . epilogue
 9710     89/<- %esp 5/r32/ebp
 9711     5d/pop-to-ebp
 9712     c3/return
 9713 
 9714 append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
 9715     # . prologue
 9716     55/push-ebp
 9717     89/<- %ebp 4/r32/esp
 9718     # . save registers
 9719     50/push-eax
 9720     56/push-esi
 9721     # esi = block
 9722     8b/-> *(ebp+0xc) 6/r32/esi
 9723     # block->stmts = append(x, block->stmts)
 9724     8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
 9725     (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
 9726 $append-to-block:end:
 9727     # . restore registers
 9728     5e/pop-to-esi
 9729     58/pop-to-eax
 9730     # . epilogue
 9731     89/<- %esp 5/r32/ebp
 9732     5d/pop-to-ebp
 9733     c3/return
 9734 
 9735 ## Parsing types
 9736 # We need to create metadata on user-defined types, and we need to use this
 9737 # metadata as we parse instructions.
 9738 # However, we also want to allow types to be used before their definitions.
 9739 # This means we can't ever assume any type data structures exist.
 9740 
 9741 lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
 9742     # . prologue
 9743     55/push-ebp
 9744     89/<- %ebp 4/r32/esp
 9745     # . save registers
 9746     50/push-eax
 9747     56/push-esi
 9748     # var container-type/esi: type-id
 9749     (container-type *(ebp+8))  # => eax
 9750     89/<- %esi 0/r32/eax
 9751     # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
 9752     68/push 0/imm32
 9753     68/push 0/imm32
 9754     89/<- %eax 4/r32/esp
 9755     (find-or-create-typeinfo %esi %eax)
 9756     # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
 9757     (lookup *eax *(eax+4))  # => eax
 9758     # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
 9759 #?     (write-buffered Stderr "constant: ")
 9760 #?     (write-slice-buffered Stderr *(ebp+0xc))
 9761 #?     (write-buffered Stderr Newline)
 9762 #?     (flush Stderr)
 9763     (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
 9764 #?     8b/-> *(ebp+0x10) 0/r32/eax
 9765 #?     (write-buffered Stderr "@")
 9766 #?     (lookup *eax *(eax+4))
 9767 #?     (write-int32-hex-buffered Stderr %eax)
 9768 #?     (lookup *eax *(eax+4))
 9769 #?     (write-buffered Stderr %eax)
 9770 #?     (write-buffered Stderr Newline)
 9771 #?     (flush Stderr)
 9772 #?     (write-buffered Stderr "offset: ")
 9773 #?     8b/-> *(eax+0x14) 0/r32/eax
 9774 #?     (write-int32-hex-buffered Stderr %eax)
 9775 #?     (write-buffered Stderr Newline)
 9776 #?     (flush Stderr)
 9777 $lookup-or-create-constant:end:
 9778     # . reclaim locals
 9779     81 0/subop/add %esp 8/imm32
 9780     # . restore registers
 9781     5e/pop-to-esi
 9782     58/pop-to-eax
 9783     # . epilogue
 9784     89/<- %esp 5/r32/ebp
 9785     5d/pop-to-ebp
 9786     c3/return
 9787 
 9788 # if addr var:
 9789 #   container->var->type->right->left->value
 9790 # otherwise
 9791 #   container->var->type->value
 9792 container-type:  # container: (addr stmt-var) -> result/eax: type-id
 9793     # . prologue
 9794     55/push-ebp
 9795     89/<- %ebp 4/r32/esp
 9796     #
 9797     8b/-> *(ebp+8) 0/r32/eax
 9798     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
 9799     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
 9800     {
 9801       81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
 9802       74/jump-if-= break/disp8
 9803       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
 9804       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
 9805     }
 9806     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
 9807 $container-type:end:
 9808     # . epilogue
 9809     89/<- %esp 5/r32/ebp
 9810     5d/pop-to-ebp
 9811     c3/return
 9812 
 9813 is-container?:  # t: type-id -> result/eax: boolean
 9814     # . prologue
 9815     55/push-ebp
 9816     89/<- %ebp 4/r32/esp
 9817     #
 9818     8b/-> *(ebp+8) 0/r32/eax
 9819     c1/shift 4/subop/left %eax 2/imm8
 9820     3b/compare 0/r32/eax *Primitive-type-ids
 9821     0f 9d/set-if->= %al
 9822     81 4/subop/and %eax 0xff/imm32
 9823 $is-container?:end:
 9824     # . epilogue
 9825     89/<- %esp 5/r32/ebp
 9826     5d/pop-to-ebp
 9827     c3/return
 9828 
 9829 find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 9830     # . prologue
 9831     55/push-ebp
 9832     89/<- %ebp 4/r32/esp
 9833     # . save registers
 9834     50/push-eax
 9835     51/push-ecx
 9836     52/push-edx
 9837     57/push-edi
 9838     # edi = out
 9839     8b/-> *(ebp+0xc) 7/r32/edi
 9840     # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
 9841     68/push 0/imm32
 9842     68/push 0/imm32
 9843     89/<- %ecx 4/r32/esp
 9844     # find-typeinfo(t, out)
 9845     (find-typeinfo *(ebp+8) %edi)
 9846     {
 9847       # if (*out != 0) break
 9848       81 7/subop/compare *edi 0/imm32
 9849       0f 85/jump-if-!= break/disp32
 9850 $find-or-create-typeinfo:create:
 9851       # *out = allocate
 9852       (allocate Heap *Typeinfo-size %edi)
 9853       # var tmp/eax: (addr typeinfo) = lookup(*out)
 9854       (lookup *edi *(edi+4))  # => eax
 9855 #?     (write-buffered Stderr "created typeinfo at ")
 9856 #?     (write-int32-hex-buffered Stderr %eax)
 9857 #?     (write-buffered Stderr " for type-id ")
 9858 #?     (write-int32-hex-buffered Stderr *(ebp+8))
 9859 #?     (write-buffered Stderr Newline)
 9860 #?     (flush Stderr)
 9861       # tmp->id = t
 9862       8b/-> *(ebp+8) 2/r32/edx
 9863       89/<- *eax 2/r32/edx  # Typeinfo-id
 9864       # tmp->fields = new table
 9865       # . fields = new table
 9866       (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
 9867       # . tmp->fields = fields
 9868       8b/-> *ecx 2/r32/edx
 9869       89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
 9870       8b/-> *(ecx+4) 2/r32/edx
 9871       89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
 9872       # tmp->next = Program->types
 9873       8b/-> *_Program-types 1/r32/ecx
 9874       89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
 9875       8b/-> *_Program-types->payload 1/r32/ecx
 9876       89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
 9877       # Program->types = out
 9878       8b/-> *edi 1/r32/ecx
 9879       89/<- *_Program-types 1/r32/ecx
 9880       8b/-> *(edi+4) 1/r32/ecx
 9881       89/<- *_Program-types->payload 1/r32/ecx
 9882     }
 9883 $find-or-create-typeinfo:end:
 9884     # . reclaim locals
 9885     81 0/subop/add %esp 8/imm32
 9886     # . restore registers
 9887     5f/pop-to-edi
 9888     5a/pop-to-edx
 9889     59/pop-to-ecx
 9890     58/pop-to-eax
 9891     # . epilogue
 9892     89/<- %esp 5/r32/ebp
 9893     5d/pop-to-ebp
 9894     c3/return
 9895 
 9896 find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
 9897     # . prologue
 9898     55/push-ebp
 9899     89/<- %ebp 4/r32/esp
 9900     # . save registers
 9901     50/push-eax
 9902     51/push-ecx
 9903     52/push-edx
 9904     57/push-edi
 9905     # ecx = t
 9906     8b/-> *(ebp+8) 1/r32/ecx
 9907     # edi = out
 9908     8b/-> *(ebp+0xc) 7/r32/edi
 9909     # *out = Program->types
 9910     8b/-> *_Program-types 0/r32/eax
 9911     89/<- *edi 0/r32/eax
 9912     8b/-> *_Program-types->payload 0/r32/eax
 9913     89/<- *(edi+4) 0/r32/eax
 9914     {
 9915 $find-typeinfo:loop:
 9916       # if (*out == 0) break
 9917       81 7/subop/compare *edi 0/imm32
 9918       74/jump-if-= break/disp8
 9919 $find-typeinfo:check:
 9920       # var tmp/eax: (addr typeinfo) = lookup(*out)
 9921       (lookup *edi *(edi+4))  # => eax
 9922       # if (tmp->id == t) break
 9923       39/compare *eax 1/r32/ecx  # Typeinfo-id
 9924       74/jump-if-= break/disp8
 9925 $find-typeinfo:continue:
 9926       # *out = tmp->next
 9927       8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
 9928       89/<- *edi 2/r32/edx
 9929       8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
 9930       89/<- *(edi+4) 2/r32/edx
 9931       #
 9932       eb/jump loop/disp8
 9933     }
 9934 $find-typeinfo:end:
 9935     # . restore registers
 9936     5f/pop-to-edi
 9937     5a/pop-to-edx
 9938     59/pop-to-ecx
 9939     58/pop-to-eax
 9940     # . epilogue
 9941     89/<- %esp 5/r32/ebp
 9942     5d/pop-to-ebp
 9943     c3/return
 9944 
 9945 find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
 9946     # . prologue
 9947     55/push-ebp
 9948     89/<- %ebp 4/r32/esp
 9949     # . save registers
 9950     50/push-eax
 9951     52/push-edx
 9952     57/push-edi
 9953     # var dest/edi: (handle typeinfo-entry)
 9954     68/push 0/imm32
 9955     68/push 0/imm32
 9956     89/<- %edi 4/r32/esp
 9957     # find-or-create-typeinfo-fields(T, f, dest)
 9958     (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
 9959     # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
 9960     (lookup *edi *(edi+4))  # => eax
 9961     89/<- %edi 0/r32/eax
 9962     # if dest-addr->output-var doesn't exist, create it
 9963     {
 9964       81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
 9965       0f 85/jump-if-!= break/disp32
 9966       # dest-addr->output-var = new var(dummy name, type, -1 offset)
 9967       # . var name/eax: (handle array byte) = "field"
 9968       68/push 0/imm32
 9969       68/push 0/imm32
 9970       89/<- %eax 4/r32/esp
 9971       (slice-to-string Heap *(ebp+0xc) %eax)
 9972       # . new var
 9973       8d/copy-address *(edi+0xc) 2/r32/edx
 9974       (new-var Heap  *eax *(eax+4)  %edx)
 9975       # . reclaim name
 9976       81 0/subop/add %esp 8/imm32
 9977       # var result/edx: (addr var) = lookup(dest-addr->output-var)
 9978       (lookup *(edi+0xc) *(edi+0x10))  # => eax
 9979       89/<- %edx 0/r32/eax
 9980       # result->type = new constant type
 9981       8d/copy-address *(edx+8) 0/r32/eax  # Var-type
 9982       (allocate Heap *Type-tree-size %eax)
 9983       (lookup *(edx+8) *(edx+0xc))  # => eax
 9984       c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
 9985       c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
 9986       c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
 9987       c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
 9988       c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
 9989       # result->offset isn't filled out yet
 9990       c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
 9991     }
 9992     # out = dest-addr->output-var
 9993     8b/-> *(ebp+0x10) 2/r32/edx
 9994     8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
 9995     89/<- *edx 0/r32/eax
 9996     8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
 9997     89/<- *(edx+4) 0/r32/eax
 9998 $find-or-create-typeinfo-output-var:end:
 9999     # . reclaim locals
10000     81 0/subop/add %esp 8/imm32
10001     # . restore registers
10002     5f/pop-to-edi
10003     5a/pop-to-edx
10004     58/pop-to-eax
10005     # . epilogue
10006     89/<- %esp 5/r32/ebp
10007     5d/pop-to-ebp
10008     c3/return
10009 
10010 find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
10011     # . prologue
10012     55/push-ebp
10013     89/<- %ebp 4/r32/esp
10014     # . save registers
10015     50/push-eax
10016     56/push-esi
10017     57/push-edi
10018     # eax = lookup(T->fields)
10019     8b/-> *(ebp+8) 0/r32/eax
10020     (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
10021     # edi = out
10022     8b/-> *(ebp+0x10) 7/r32/edi
10023     # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
10024     (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
10025     89/<- %esi 0/r32/eax
10026     # if src doesn't exist, allocate it
10027     {
10028       81 7/subop/compare *esi 0/imm32
10029       75/jump-if-!= break/disp8
10030       (allocate Heap *Typeinfo-entry-size %esi)
10031 #?       (write-buffered Stderr "handle at ")
10032 #?       (write-int32-hex-buffered Stderr %esi)
10033 #?       (write-buffered Stderr ": ")
10034 #?       (write-int32-hex-buffered Stderr *esi)
10035 #?       (write-buffered Stderr " ")
10036 #?       (write-int32-hex-buffered Stderr *(esi+4))
10037 #?       (write-buffered Stderr Newline)
10038 #?       (flush Stderr)
10039 #?       (lookup *esi *(esi+4))
10040 #?       (write-buffered Stderr "created typeinfo fields at ")
10041 #?       (write-int32-hex-buffered Stderr %esi)
10042 #?       (write-buffered Stderr " for ")
10043 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10044 #?       (write-buffered Stderr Newline)
10045 #?       (flush Stderr)
10046     }
10047     # *out = src
10048     # . *edi = *src
10049     8b/-> *esi 0/r32/eax
10050     89/<- *edi 0/r32/eax
10051     8b/-> *(esi+4) 0/r32/eax
10052     89/<- *(edi+4) 0/r32/eax
10053 $find-or-create-typeinfo-fields:end:
10054     # . restore registers
10055     5f/pop-to-edi
10056     5e/pop-to-esi
10057     58/pop-to-eax
10058     # . epilogue
10059     89/<- %esp 5/r32/ebp
10060     5d/pop-to-ebp
10061     c3/return
10062 
10063 populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10064     # pseudocode:
10065     #   var line: (stream byte 512)
10066     #   curr-index = 0
10067     #   while true
10068     #     clear-stream(line)
10069     #     read-line-buffered(in, line)
10070     #     if line->write == 0
10071     #       abort
10072     #     word-slice = next-mu-token(line)
10073     #     if slice-empty?(word-slice)               # end of line
10074     #       continue
10075     #     if slice-equal?(word-slice, "}")
10076     #       break
10077     #     var v: (handle var) = parse-var-with-type(word-slice, line)
10078     #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
10079     #     TODO: ensure that r->first is null
10080     #     r->index = curr-index
10081     #     curr-index++
10082     #     r->input-var = v
10083     #     if r->output-var == 0
10084     #       r->output-var = new literal
10085     #     TODO: ensure nothing else in line
10086     # t->total-size-in-bytes = -2 (not yet initialized)
10087     #
10088     # . prologue
10089     55/push-ebp
10090     89/<- %ebp 4/r32/esp
10091     # var curr-index: int at *(ebp-4)
10092     68/push 0/imm32
10093     # . save registers
10094     50/push-eax
10095     51/push-ecx
10096     52/push-edx
10097     53/push-ebx
10098     56/push-esi
10099     57/push-edi
10100     # edi = t
10101     8b/-> *(ebp+0xc) 7/r32/edi
10102     # var line/ecx: (stream byte 512)
10103     81 5/subop/subtract %esp 0x200/imm32
10104     68/push 0x200/imm32/size
10105     68/push 0/imm32/read
10106     68/push 0/imm32/write
10107     89/<- %ecx 4/r32/esp
10108     # var word-slice/edx: slice
10109     68/push 0/imm32/end
10110     68/push 0/imm32/start
10111     89/<- %edx 4/r32/esp
10112     # var v/esi: (handle var)
10113     68/push 0/imm32
10114     68/push 0/imm32
10115     89/<- %esi 4/r32/esp
10116     # var r/ebx: (handle typeinfo-entry)
10117     68/push 0/imm32
10118     68/push 0/imm32
10119     89/<- %ebx 4/r32/esp
10120     {
10121 $populate-mu-type:line-loop:
10122       (clear-stream %ecx)
10123       (read-line-buffered *(ebp+8) %ecx)
10124       # if (line->write == 0) abort
10125       81 7/subop/compare *ecx 0/imm32
10126       0f 84/jump-if-= $populate-mu-type:abort/disp32
10127 +--  6 lines: #?       # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------
10133       (next-mu-token %ecx %edx)
10134       # if slice-empty?(word-slice) continue
10135       (slice-empty? %edx)  # => eax
10136       3d/compare-eax-and 0/imm32
10137       0f 85/jump-if-!= loop/disp32
10138       # if slice-equal?(word-slice, "}") break
10139       (slice-equal? %edx "}")
10140       3d/compare-eax-and 0/imm32
10141       0f 85/jump-if-!= break/disp32
10142 $populate-mu-type:parse-element:
10143       # v = parse-var-with-type(word-slice, first-line)
10144       # must do this first to strip the trailing ':' from word-slice before
10145       # using it in find-or-create-typeinfo-fields below
10146       # TODO: clean up that mutation in parse-var-with-type
10147       (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))  # => eax
10148       # var tmp/ecx
10149       51/push-ecx
10150 $populate-mu-type:create-typeinfo-fields:
10151       # var r/ebx: (handle typeinfo-entry)
10152       (find-or-create-typeinfo-fields %edi %edx %ebx)
10153       # r->index = curr-index
10154       (lookup *ebx *(ebx+4))  # => eax
10155       8b/-> *(ebp-4) 1/r32/ecx
10156 #?       (write-buffered Stderr "saving index ")
10157 #?       (write-int32-hex-buffered Stderr %ecx)
10158 #?       (write-buffered Stderr " at ")
10159 #?       (write-int32-hex-buffered Stderr %edi)
10160 #?       (write-buffered Stderr Newline)
10161 #?       (flush Stderr)
10162       89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
10163       # ++curr-index
10164       ff 0/subop/increment *(ebp-4)
10165 $populate-mu-type:set-input-type:
10166       # r->input-var = v
10167       8b/-> *esi 1/r32/ecx
10168       89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
10169       8b/-> *(esi+4) 1/r32/ecx
10170       89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
10171       59/pop-to-ecx
10172       {
10173 $populate-mu-type:create-output-type:
10174         # if (r->output-var == 0) create a new var with some placeholder data
10175         81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
10176         75/jump-if-!= break/disp8
10177         8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10178         (new-literal Heap %edx %eax)
10179       }
10180       e9/jump loop/disp32
10181     }
10182 $populate-mu-type:invalidate-total-size-in-bytes:
10183     # Offsets and total size may not be accurate here since we may not yet
10184     # have encountered the element types.
10185     # We'll recompute them separately after parsing the entire program.
10186     c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
10187 $populate-mu-type:end:
10188     # . reclaim locals
10189     81 0/subop/add %esp 0x224/imm32
10190     # . restore registers
10191     5f/pop-to-edi
10192     5e/pop-to-esi
10193     5b/pop-to-ebx
10194     5a/pop-to-edx
10195     59/pop-to-ecx
10196     58/pop-to-eax
10197     # reclaim curr-index
10198     81 0/subop/add %esp 4/imm32
10199     # . epilogue
10200     89/<- %esp 5/r32/ebp
10201     5d/pop-to-ebp
10202     c3/return
10203 
10204 $populate-mu-type:abort:
10205     # error("unexpected top-level command: " word-slice "\n")
10206     (write-buffered *(ebp+0x10) "incomplete type definition '")
10207     (type-name *edi)  # Typeinfo-id => eax
10208     (write-buffered *(ebp+0x10) %eax)
10209     (write-buffered *(ebp+0x10) "\n")
10210     (flush *(ebp+0x10))
10211     (stop *(ebp+0x14) 1)
10212     # never gets here
10213 
10214 type-name:  # index: int -> result/eax: (addr array byte)
10215     # . prologue
10216     55/push-ebp
10217     89/<- %ebp 4/r32/esp
10218     #
10219     (index Type-id *(ebp+8))
10220 $type-name:end:
10221     # . epilogue
10222     89/<- %esp 5/r32/ebp
10223     5d/pop-to-ebp
10224     c3/return
10225 
10226 index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
10227     # . prologue
10228     55/push-ebp
10229     89/<- %ebp 4/r32/esp
10230     # . save registers
10231     56/push-esi
10232     # TODO: bounds-check index
10233     # esi = arr
10234     8b/-> *(ebp+8) 6/r32/esi
10235     # eax = index
10236     8b/-> *(ebp+0xc) 0/r32/eax
10237     # eax = *(arr + 12 + index)
10238     8b/-> *(esi+eax+0xc) 0/r32/eax
10239 $index:end:
10240     # . restore registers
10241     5e/pop-to-esi
10242     # . epilogue
10243     89/<- %esp 5/r32/ebp
10244     5d/pop-to-ebp
10245     c3/return
10246 
10247 #######################################################
10248 # Compute type sizes
10249 #######################################################
10250 
10251 # Compute the sizes of all user-defined types.
10252 # We'll need the sizes of their elements, which may be other user-defined
10253 # types, which we will compute as needed.
10254 
10255 # Initially, all user-defined types have their sizes set to -2 (invalid)
10256 populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
10257     # . prologue
10258     55/push-ebp
10259     89/<- %ebp 4/r32/esp
10260 $populate-mu-type-sizes:total-sizes:
10261     # var curr/eax: (addr typeinfo) = lookup(Program->types)
10262     (lookup *_Program-types *_Program-types->payload)  # => eax
10263     {
10264       # if (curr == null) break
10265       3d/compare-eax-and 0/imm32/null
10266       74/jump-if-= break/disp8
10267       (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
10268       # curr = lookup(curr->next)
10269       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10270       eb/jump loop/disp8
10271     }
10272 $populate-mu-type-sizes:offsets:
10273     # curr = *Program->types
10274     (lookup *_Program-types *_Program-types->payload)  # => eax
10275     {
10276       # if (curr == null) break
10277       3d/compare-eax-and 0/imm32/null
10278       74/jump-if-= break/disp8
10279       (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
10280       # curr = curr->next
10281       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10282       eb/jump loop/disp8
10283     }
10284 $populate-mu-type-sizes:end:
10285     # . epilogue
10286     89/<- %esp 5/r32/ebp
10287     5d/pop-to-ebp
10288     c3/return
10289 
10290 # compute sizes of all fields, recursing as necessary
10291 # sum up all their sizes to arrive at total size
10292 # fields may be out of order, but that doesn't affect the answer
10293 populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10294     # . prologue
10295     55/push-ebp
10296     89/<- %ebp 4/r32/esp
10297     # . save registers
10298     50/push-eax
10299     51/push-ecx
10300     52/push-edx
10301     56/push-esi
10302     57/push-edi
10303     # esi = T
10304     8b/-> *(ebp+8) 6/r32/esi
10305     # if T is already computed, return
10306     81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
10307     0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
10308     # if T is being computed, abort
10309     81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10310     0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
10311     # tag T (-2 to -1) to avoid infinite recursion
10312     c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
10313     # var total-size/edi: int = 0
10314     bf/copy-to-edi 0/imm32
10315     # - for every field, if it's a user-defined type, compute its size
10316     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
10317     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
10318     89/<- %ecx 0/r32/eax
10319     # var table-size/edx: int = table->write
10320     8b/-> *ecx 2/r32/edx  # stream-write
10321     # var curr/ecx: (addr table_row) = table->data
10322     8d/copy-address *(ecx+0xc) 1/r32/ecx
10323     # var max/edx: (addr table_row) = table->data + table->write
10324     8d/copy-address *(ecx+edx) 2/r32/edx
10325     {
10326 $populate-mu-type-sizes-in-type:loop:
10327       # if (curr >= max) break
10328       39/compare %ecx 2/r32/edx
10329       73/jump-if-addr>= break/disp8
10330       # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
10331       (lookup *(ecx+8) *(ecx+0xc))  # => eax
10332       # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
10333       81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
10334       74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
10335       # compute size of t->input-var
10336       (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
10337       (compute-size-of-var %eax)  # => eax
10338       # result += eax
10339       01/add-to %edi 0/r32/eax
10340       # curr += row-size
10341       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
10342       #
10343       eb/jump loop/disp8
10344     }
10345     # - save result
10346     89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
10347 $populate-mu-type-sizes-in-type:end:
10348     # . restore registers
10349     5f/pop-to-edi
10350     5e/pop-to-esi
10351     5a/pop-to-edx
10352     59/pop-to-ecx
10353     58/pop-to-eax
10354     # . epilogue
10355     89/<- %esp 5/r32/ebp
10356     5d/pop-to-ebp
10357     c3/return
10358 
10359 $populate-mu-type-sizes-in-type:abort:
10360     (write-buffered *(ebp+0xc) "cycle in type definitions\n")
10361     (flush *(ebp+0xc))
10362     (stop *(ebp+0x10) 1)
10363     # never gets here
10364 
10365 # Analogous to size-of, except we need to compute what size-of can just read
10366 # off the right data structures.
10367 compute-size-of-var:  # in: (addr var) -> result/eax: int
10368     # . prologue
10369     55/push-ebp
10370     89/<- %ebp 4/r32/esp
10371     # . push registers
10372     51/push-ecx
10373     # var t/ecx: (addr type-tree) = lookup(v->type)
10374     8b/-> *(ebp+8) 1/r32/ecx
10375     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
10376     89/<- %ecx 0/r32/eax
10377     # if (t->is-atom == false) t = lookup(t->left)
10378     {
10379       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
10380       75/jump-if-!= break/disp8
10381       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
10382       89/<- %ecx 0/r32/eax
10383     }
10384     # TODO: ensure t is an atom
10385     (compute-size-of-type-id *(ecx+4))  # Type-tree-value => eax
10386 $compute-size-of-var:end:
10387     # . restore registers
10388     59/pop-to-ecx
10389     # . epilogue
10390     89/<- %esp 5/r32/ebp
10391     5d/pop-to-ebp
10392     c3/return
10393 
10394 compute-size-of-type-id:  # t: type-id -> result/eax: int
10395     # . prologue
10396     55/push-ebp
10397     89/<- %ebp 4/r32/esp
10398     # . save registers
10399     51/push-ecx
10400     # var out/ecx: (handle typeinfo)
10401     68/push 0/imm32
10402     68/push 0/imm32
10403     89/<- %ecx 4/r32/esp
10404     # eax = t
10405     8b/-> *(ebp+8) 0/r32/eax
10406     # if t is a literal, return 0
10407     3d/compare-eax-and 0/imm32/literal
10408     0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
10409     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
10410     3d/compare-eax-and 8/imm32/byte
10411     {
10412       75/jump-if-!= break/disp8
10413       b8/copy-to-eax 4/imm32
10414       eb/jump $compute-size-of-type-id:end/disp8
10415     }
10416     # if t is a handle, return 8
10417     3d/compare-eax-and 4/imm32/handle
10418     {
10419       75/jump-if-!= break/disp8
10420       b8/copy-to-eax 8/imm32
10421       eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
10422     }
10423     # if t is a user-defined type, compute its size
10424     # TODO: support non-atom type
10425     (find-typeinfo %eax %ecx)
10426     {
10427       81 7/subop/compare *ecx 0/imm32
10428       74/jump-if-= break/disp8
10429 $compute-size-of-type-id:user-defined:
10430       (populate-mu-type-sizes %eax)
10431       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
10432       eb/jump $compute-size-of-type-id:end/disp8
10433     }
10434     # otherwise return the word size
10435     b8/copy-to-eax 4/imm32
10436 $compute-size-of-type-id:end:
10437     # . reclaim locals
10438     81 0/subop/add %esp 8/imm32
10439     # . restore registers
10440     59/pop-to-ecx
10441     # . epilogue
10442     89/<- %esp 5/r32/ebp
10443     5d/pop-to-ebp
10444     c3/return
10445 
10446 # at this point we have total sizes for all user-defined types
10447 # compute offsets for each element
10448 # complication: fields may be out of order
10449 populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
10450     # . prologue
10451     55/push-ebp
10452     89/<- %ebp 4/r32/esp
10453     # . save registers
10454     50/push-eax
10455     51/push-ecx
10456     52/push-edx
10457     53/push-ebx
10458     56/push-esi
10459     57/push-edi
10460 #?     (dump-typeinfos "aaa\n")
10461     # var curr-offset/edi: int = 0
10462     bf/copy-to-edi 0/imm32
10463     # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
10464     8b/-> *(ebp+8) 1/r32/ecx
10465     (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
10466     89/<- %ecx 0/r32/eax
10467     # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
10468     8b/-> *ecx 2/r32/edx  # stream-write
10469     c1 5/subop/shift-right-logical  %edx 4/imm8
10470     # var i/ebx: int = 0
10471     bb/copy-to-ebx 0/imm32
10472     {
10473 $populate-mu-type-offsets:loop:
10474       39/compare %ebx 2/r32/edx
10475       0f 8d/jump-if->= break/disp32
10476 #?       (write-buffered Stderr "looking up index ")
10477 #?       (write-int32-hex-buffered Stderr %ebx)
10478 #?       (write-buffered Stderr " in ")
10479 #?       (write-int32-hex-buffered Stderr *(ebp+8))
10480 #?       (write-buffered Stderr Newline)
10481 #?       (flush Stderr)
10482       # var v/esi: (addr typeinfo-entry)
10483       (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
10484       89/<- %esi 0/r32/eax
10485       # if v is null, silently move on; we'll emit a nice error message while type-checking
10486       81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
10487       74/jump-if-= $populate-mu-type-offsets:end/disp8
10488       # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
10489       81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
10490       74/jump-if-= $populate-mu-type-offsets:end/disp8
10491       # v->output-var->offset = curr-offset
10492       # . eax: (addr var)
10493       (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
10494       89/<- *(eax+0x14) 7/r32/edi  # Var-offset
10495       # curr-offset += size-of(v->input-var)
10496       (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
10497       (size-of %eax)  # => eax
10498       01/add-to %edi 0/r32/eax
10499       # ++i
10500       43/increment-ebx
10501       e9/jump loop/disp32
10502     }
10503 $populate-mu-type-offsets:end:
10504     # . restore registers
10505     5f/pop-to-edi
10506     5e/pop-to-esi
10507     5b/pop-to-ebx
10508     5a/pop-to-edx
10509     59/pop-to-ecx
10510     58/pop-to-eax
10511     # . epilogue
10512     89/<- %esp 5/r32/ebp
10513     5d/pop-to-ebp
10514     c3/return
10515 
10516 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)
10517     # . prologue
10518     55/push-ebp
10519     89/<- %ebp 4/r32/esp
10520     # . save registers
10521     51/push-ecx
10522     52/push-edx
10523     53/push-ebx
10524     56/push-esi
10525     57/push-edi
10526     # esi = table
10527     8b/-> *(ebp+8) 6/r32/esi
10528     # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
10529     8d/copy-address *(esi+0xc) 1/r32/ecx
10530     # var max/edx: (addr byte) = &table->data[table->write]
10531     8b/-> *esi 2/r32/edx
10532     8d/copy-address *(ecx+edx) 2/r32/edx
10533     {
10534 $locate-typeinfo-entry-with-index:loop:
10535       39/compare %ecx 2/r32/edx
10536       73/jump-if-addr>= break/disp8
10537       # var v/eax: (addr typeinfo-entry)
10538       (lookup *(ecx+8) *(ecx+0xc))  # => eax
10539       # if (v->index == idx) return v
10540       8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
10541 #?       (write-buffered Stderr "comparing ")
10542 #?       (write-int32-hex-buffered Stderr %ebx)
10543 #?       (write-buffered Stderr " and ")
10544 #?       (write-int32-hex-buffered Stderr *(ebp+0xc))
10545 #?       (write-buffered Stderr Newline)
10546 #?       (flush Stderr)
10547       39/compare *(ebp+0xc) 3/r32/ebx
10548       74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
10549       # curr += Typeinfo-entry-size
10550       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
10551       #
10552       eb/jump loop/disp8
10553     }
10554     # return 0
10555     b8/copy-to-eax 0/imm32
10556 $locate-typeinfo-entry-with-index:end:
10557 #?     (write-buffered Stderr "returning ")
10558 #?     (write-int32-hex-buffered Stderr %eax)
10559 #?     (write-buffered Stderr Newline)
10560 #?     (flush Stderr)
10561     # . restore registers
10562     5f/pop-to-edi
10563     5e/pop-to-esi
10564     5b/pop-to-ebx
10565     5a/pop-to-edx
10566     59/pop-to-ecx
10567     # . epilogue
10568     89/<- %esp 5/r32/ebp
10569     5d/pop-to-ebp
10570     c3/return
10571 
10572 dump-typeinfos:  # hdr: (addr array byte)
10573     # . prologue
10574     55/push-ebp
10575     89/<- %ebp 4/r32/esp
10576     # . save registers
10577     50/push-eax
10578     #
10579     (write-buffered Stderr *(ebp+8))
10580     (flush Stderr)
10581     # var curr/eax: (addr typeinfo) = lookup(Program->types)
10582     (lookup *_Program-types *_Program-types->payload)  # => eax
10583     {
10584       # if (curr == null) break
10585       3d/compare-eax-and 0/imm32
10586       74/jump-if-= break/disp8
10587       (write-buffered Stderr "---\n")
10588       (flush Stderr)
10589       (dump-typeinfo %eax)
10590       # curr = lookup(curr->next)
10591       (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
10592       eb/jump loop/disp8
10593     }
10594 $dump-typeinfos:end:
10595     # . restore registers
10596     58/pop-to-eax
10597     # . epilogue
10598     89/<- %esp 5/r32/ebp
10599     5d/pop-to-ebp
10600     c3/return
10601 
10602 dump-typeinfo:  # in: (addr typeinfo)
10603     # . prologue
10604     55/push-ebp
10605     89/<- %ebp 4/r32/esp
10606     # . save registers
10607     50/push-eax
10608     51/push-ecx
10609     52/push-edx
10610     53/push-ebx
10611     56/push-esi
10612     57/push-edi
10613     # esi = in
10614     8b/-> *(ebp+8) 6/r32/esi
10615     # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
10616     (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
10617     89/<- %ecx 0/r32/eax
10618     (write-buffered Stderr "id:")
10619     (write-int32-hex-buffered Stderr *esi)
10620     (write-buffered Stderr "\n")
10621     (write-buffered Stderr "fields @ ")
10622     (write-int32-hex-buffered Stderr %ecx)
10623     (write-buffered Stderr Newline)
10624     (flush Stderr)
10625     (write-buffered Stderr "  write: ")
10626     (write-int32-hex-buffered Stderr *ecx)
10627     (write-buffered Stderr Newline)
10628     (flush Stderr)
10629     (write-buffered Stderr "  read: ")
10630     (write-int32-hex-buffered Stderr *(ecx+4))
10631     (write-buffered Stderr Newline)
10632     (flush Stderr)
10633     (write-buffered Stderr "  size: ")
10634     (write-int32-hex-buffered Stderr *(ecx+8))
10635     (write-buffered Stderr Newline)
10636     (flush Stderr)
10637     # var table-size/edx: int = table->write
10638     8b/-> *ecx 2/r32/edx  # stream-write
10639     # var curr/ecx: (addr table_row) = table->data
10640     8d/copy-address *(ecx+0xc) 1/r32/ecx
10641     # var max/edx: (addr table_row) = table->data + table->write
10642     8d/copy-address *(ecx+edx) 2/r32/edx
10643     {
10644 $dump-typeinfo:loop:
10645       # if (curr >= max) break
10646       39/compare %ecx 2/r32/edx
10647       0f 83/jump-if-addr>= break/disp32
10648       (write-buffered Stderr "  row:\n")
10649       (write-buffered Stderr "    key: ")
10650       (write-int32-hex-buffered Stderr *ecx)
10651       (write-buffered Stderr ",")
10652       (write-int32-hex-buffered Stderr *(ecx+4))
10653       (write-buffered Stderr " = '")
10654       (lookup *ecx *(ecx+4))
10655       (write-buffered Stderr %eax)
10656       (write-buffered Stderr "' @ ")
10657       (write-int32-hex-buffered Stderr %eax)
10658       (write-buffered Stderr Newline)
10659       (flush Stderr)
10660       (write-buffered Stderr "    value: ")
10661       (write-int32-hex-buffered Stderr *(ecx+8))
10662       (write-buffered Stderr ",")
10663       (write-int32-hex-buffered Stderr *(ecx+0xc))
10664       (write-buffered Stderr " = typeinfo-entry@")
10665       (lookup *(ecx+8) *(ecx+0xc))
10666       (write-int32-hex-buffered Stderr %eax)
10667       (write-buffered Stderr Newline)
10668       (flush Stderr)
10669       (write-buffered Stderr "        input var@")
10670       (dump-var 5 %eax)
10671       (lookup *(ecx+8) *(ecx+0xc))
10672       (write-buffered Stderr "        index: ")
10673       (write-int32-hex-buffered Stderr *(eax+8))
10674       (write-buffered Stderr Newline)
10675       (flush Stderr)
10676       (write-buffered Stderr "        output var@")
10677       8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
10678       (dump-var 5 %eax)
10679       (flush Stderr)
10680       # curr += row-size
10681       81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
10682       #
10683       e9/jump loop/disp32
10684     }
10685 $dump-typeinfo:end:
10686     # . restore registers
10687     5f/pop-to-edi
10688     5e/pop-to-esi
10689     5b/pop-to-ebx
10690     5a/pop-to-edx
10691     59/pop-to-ecx
10692     58/pop-to-eax
10693     # . epilogue
10694     89/<- %esp 5/r32/ebp
10695     5d/pop-to-ebp
10696     c3/return
10697 
10698 dump-var:  # indent: int, v: (addr handle var)
10699     # . prologue
10700     55/push-ebp
10701     89/<- %ebp 4/r32/esp
10702     # . save registers
10703     50/push-eax
10704     53/push-ebx
10705     # eax = v
10706     8b/-> *(ebp+0xc) 0/r32/eax
10707     #
10708     (write-int32-hex-buffered Stderr *eax)
10709     (write-buffered Stderr ",")
10710     (write-int32-hex-buffered Stderr *(eax+4))
10711     (write-buffered Stderr "->")
10712     (lookup *eax *(eax+4))
10713     (write-int32-hex-buffered Stderr %eax)
10714     (write-buffered Stderr Newline)
10715     (flush Stderr)
10716     {
10717       3d/compare-eax-and 0/imm32
10718       0f 84/jump-if-= break/disp32
10719       (emit-indent Stderr *(ebp+8))
10720       (write-buffered Stderr "name: ")
10721       89/<- %ebx 0/r32/eax
10722       (write-int32-hex-buffered Stderr *ebx)  # Var-name
10723       (write-buffered Stderr ",")
10724       (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
10725       (write-buffered Stderr "->")
10726       (lookup *ebx *(ebx+4))  # Var-name
10727       (write-int32-hex-buffered Stderr %eax)
10728       {
10729         3d/compare-eax-and 0/imm32
10730         74/jump-if-= break/disp8
10731         (write-buffered Stderr Space)
10732         (write-buffered Stderr %eax)
10733       }
10734       (write-buffered Stderr Newline)
10735       (flush Stderr)
10736       (emit-indent Stderr *(ebp+8))
10737       (write-buffered Stderr "block depth: ")
10738       (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
10739       (write-buffered Stderr Newline)
10740       (flush Stderr)
10741       (emit-indent Stderr *(ebp+8))
10742       (write-buffered Stderr "stack offset: ")
10743       (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
10744       (write-buffered Stderr Newline)
10745       (flush Stderr)
10746       (emit-indent Stderr *(ebp+8))
10747       (write-buffered Stderr "reg: ")
10748       (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
10749       (write-buffered Stderr ",")
10750       (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
10751       (write-buffered Stderr "->")
10752       (flush Stderr)
10753       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
10754       (write-int32-hex-buffered Stderr %eax)
10755       {
10756         3d/compare-eax-and 0/imm32
10757         74/jump-if-= break/disp8
10758         (write-buffered Stderr Space)
10759         (write-buffered Stderr %eax)
10760       }
10761       (write-buffered Stderr Newline)
10762       (flush Stderr)
10763     }
10764 $dump-var:end:
10765     # . restore registers
10766     5b/pop-to-ebx
10767     58/pop-to-eax
10768     # . epilogue
10769     89/<- %esp 5/r32/ebp
10770     5d/pop-to-ebp
10771     c3/return
10772 
10773 #######################################################
10774 # Type-checking
10775 #######################################################
10776 
10777 check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
10778     # . prologue
10779     55/push-ebp
10780     89/<- %ebp 4/r32/esp
10781     # . save registers
10782     50/push-eax
10783     # var curr/eax: (addr function) = lookup(Program->functions)
10784     (lookup *_Program-functions *_Program-functions->payload)  # => eax
10785     {
10786 $check-mu-types:loop:
10787       # if (curr == null) break
10788       3d/compare-eax-and 0/imm32
10789       0f 84/jump-if-= break/disp32
10790 +--  8 lines: #?       # dump curr->name ------------------------------------------------------------------------------------------------------------------------------------------------
10798       (check-mu-function %eax *(ebp+8) *(ebp+0xc))
10799       # curr = lookup(curr->next)
10800       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
10801       e9/jump loop/disp32
10802     }
10803 $check-mu-types:end:
10804     # . restore registers
10805     58/pop-to-eax
10806     # . epilogue
10807     89/<- %esp 5/r32/ebp
10808     5d/pop-to-ebp
10809     c3/return
10810 
10811 check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10812     # . prologue
10813     55/push-ebp
10814     89/<- %ebp 4/r32/esp
10815     # . save registers
10816     50/push-eax
10817     # eax = f
10818     8b/-> *(ebp+8) 0/r32/eax
10819     # TODO: anything to check in header?
10820     # var body/eax: (addr block) = lookup(f->body)
10821     (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
10822     (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
10823 $check-mu-function:end:
10824     # . restore registers
10825     58/pop-to-eax
10826     # . epilogue
10827     89/<- %esp 5/r32/ebp
10828     5d/pop-to-ebp
10829     c3/return
10830 
10831 check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10832     # . prologue
10833     55/push-ebp
10834     89/<- %ebp 4/r32/esp
10835     # . save registers
10836     50/push-eax
10837     # eax = block
10838     8b/-> *(ebp+8) 0/r32/eax
10839     # var stmts/eax: (addr list stmt) = lookup(block->statements)
10840     (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
10841     #
10842     {
10843 $check-mu-block:check-empty:
10844       3d/compare-eax-and 0/imm32
10845       0f 84/jump-if-= break/disp32
10846       # emit block->statements
10847       (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10848     }
10849 $check-mu-block:end:
10850     # . restore registers
10851     58/pop-to-eax
10852     # . epilogue
10853     89/<- %esp 5/r32/ebp
10854     5d/pop-to-ebp
10855     c3/return
10856 
10857 check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10858     # . prologue
10859     55/push-ebp
10860     89/<- %ebp 4/r32/esp
10861     # . save registers
10862     50/push-eax
10863     56/push-esi
10864     # esi = stmts
10865     8b/-> *(ebp+8) 6/r32/esi
10866     {
10867 $check-mu-stmt-list:loop:
10868       81 7/subop/compare %esi 0/imm32
10869       0f 84/jump-if-= break/disp32
10870       # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
10871       (lookup *esi *(esi+4))  # List-value List-value => eax
10872       {
10873 $check-mu-stmt-list:check-for-block:
10874         81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
10875         75/jump-if-!= break/disp8
10876 $check-mu-stmt-list:block:
10877         (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10878         eb/jump $check-mu-stmt-list:continue/disp8
10879       }
10880       {
10881 $check-mu-stmt-list:check-for-stmt1:
10882         81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
10883         0f 85/jump-if-!= break/disp32
10884 $check-mu-stmt-list:stmt1:
10885         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10886         eb/jump $check-mu-stmt-list:continue/disp8
10887       }
10888       {
10889 $check-mu-stmt-list:check-for-reg-var-def:
10890         81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
10891         0f 85/jump-if-!= break/disp32
10892 $check-mu-stmt-list:reg-var-def:
10893         (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10894         eb/jump $check-mu-stmt-list:continue/disp8
10895       }
10896 $check-mu-stmt-list:continue:
10897       # TODO: raise an error on unrecognized Stmt-tag
10898       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
10899       89/<- %esi 0/r32/eax
10900       e9/jump loop/disp32
10901     }
10902 $check-mu-stmt-list:end:
10903     # . restore registers
10904     5e/pop-to-esi
10905     58/pop-to-eax
10906     # . epilogue
10907     89/<- %esp 5/r32/ebp
10908     5d/pop-to-ebp
10909     c3/return
10910 
10911 check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
10912     # . prologue
10913     55/push-ebp
10914     89/<- %ebp 4/r32/esp
10915     # . save registers
10916     50/push-eax
10917     # - if stmt's operation matches a primitive, check against it
10918     (has-primitive-name? *(ebp+8))  # => eax
10919     3d/compare-eax-and 0/imm32/false
10920     {
10921       74/jump-if-= break/disp8
10922       (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10923       e9/jump $check-mu-stmt:end/disp32
10924     }
10925     # - otherwise find a function to check against
10926     # var f/eax: (addr function) = lookup(*Program->functions)
10927     (lookup *_Program-functions *_Program-functions->payload)  # => eax
10928     (find-matching-function %eax *(ebp+8))  # => eax
10929     3d/compare-eax-and 0/imm32
10930     {
10931       74/jump-if-= break/disp8
10932       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10933       eb/jump $check-mu-stmt:end/disp8
10934     }
10935     # var f/eax: (addr function) = lookup(*Program->signatures)
10936     (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
10937     (find-matching-function %eax *(ebp+8))  # => eax
10938     3d/compare-eax-and 0/imm32
10939     {
10940       74/jump-if-= break/disp8
10941       (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
10942       eb/jump $check-mu-stmt:end/disp8
10943     }
10944     # - otherwise abort
10945     e9/jump $check-mu-stmt:unknown-call/disp32
10946 $check-mu-stmt:end:
10947     # . restore registers
10948     58/pop-to-eax
10949     # . epilogue
10950     89/<- %esp 5/r32/ebp
10951     5d/pop-to-ebp
10952     c3/return
10953 
10954 $check-mu-stmt:unknown-call:
10955     (write-buffered *(ebp+0x10) "unknown function '")
10956     8b/-> *(ebp+8) 0/r32/eax
10957     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
10958     (write-buffered *(ebp+0x10) %eax)
10959     (write-buffered *(ebp+0x10) "'\n")
10960     (flush *(ebp+0x10))
10961     (stop *(ebp+0x14) 1)
10962     # never gets here
10963 
10964 has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
10965     # . prologue
10966     55/push-ebp
10967     89/<- %ebp 4/r32/esp
10968     # . save registers
10969     51/push-ecx
10970     56/push-esi
10971     # var name/esi: (addr array byte) = lookup(stmt->operation)
10972     8b/-> *(ebp+8) 6/r32/esi
10973     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
10974     89/<- %esi 0/r32/eax
10975     # if (name == "get") return true
10976     (string-equal? %esi "get")  # => eax
10977     3d/compare-eax-and 0/imm32/false
10978     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10979     # if (name == "index") return true
10980     (string-equal? %esi "index")  # => eax
10981     3d/compare-eax-and 0/imm32/false
10982     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10983     # if (name == "length") return true
10984     (string-equal? %esi "length")  # => eax
10985     3d/compare-eax-and 0/imm32/false
10986     0f 85/jump-if-!= $has-primitive-name?:end/disp32
10987     # if (name == "compute-offset") return true
10988     (string-equal? %esi "compute-offset")  # => eax
10989     3d/compare-eax-and 0/imm32/false
10990     75/jump-if-!= $has-primitive-name?:end/disp8
10991     # if (name == "lookup") return true
10992     (string-equal? %esi "lookup")  # => eax
10993     3d/compare-eax-and 0/imm32/false
10994     75/jump-if-!= $has-primitive-name?:end/disp8
10995     # var curr/ecx: (addr primitive) = Primitives
10996     b9/copy-to-ecx Primitives/imm32
10997     {
10998 $has-primitive-name?:loop:
10999       # if (curr == null) break
11000       81 7/subop/compare %ecx 0/imm32
11001       74/jump-if-= break/disp8
11002       # if (primitive->name == name) return true
11003       (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
11004       (string-equal? %esi %eax)  # => eax
11005       3d/compare-eax-and 0/imm32/false
11006       75/jump-if-!= $has-primitive-name?:end/disp8
11007 $has-primitive-name?:next-primitive:
11008       # curr = curr->next
11009       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
11010       89/<- %ecx 0/r32/eax
11011       #
11012       e9/jump loop/disp32
11013     }
11014     # return null
11015     b8/copy-to-eax 0/imm32
11016 $has-primitive-name?:end:
11017     # . restore registers
11018     5e/pop-to-esi
11019     59/pop-to-ecx
11020     # . epilogue
11021     89/<- %esp 5/r32/ebp
11022     5d/pop-to-ebp
11023     c3/return
11024 
11025 check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11026     # . prologue
11027     55/push-ebp
11028     89/<- %ebp 4/r32/esp
11029     # . save registers
11030     50/push-eax
11031     51/push-ecx
11032     # var op/ecx: (addr array byte) = lookup(stmt->operation)
11033     8b/-> *(ebp+8) 0/r32/eax
11034     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11035     89/<- %ecx 0/r32/eax
11036     # if (op == "copy") check-mu-copy-stmt
11037     {
11038       (string-equal? %ecx "copy")  # => eax
11039       3d/compare-eax-and 0/imm32/false
11040       74/jump-if-= break/disp8
11041       (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11042       e9/jump $check-mu-primitive:end/disp32
11043     }
11044     # if (op == "copy-to") check-mu-copy-to-stmt
11045     {
11046       (string-equal? %ecx "copy-to")  # => eax
11047       3d/compare-eax-and 0/imm32/false
11048       74/jump-if-= break/disp8
11049       (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11050       e9/jump $check-mu-primitive:end/disp32
11051     }
11052     # if (op == "compare") check-mu-compare-stmt
11053     {
11054       (string-equal? %ecx "compare")  # => eax
11055       3d/compare-eax-and 0/imm32/false
11056       74/jump-if-= break/disp8
11057       (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11058       e9/jump $check-mu-primitive:end/disp32
11059     }
11060     # if (op == "address") check-mu-address-stmt
11061     {
11062       (string-equal? %ecx "address")  # => eax
11063       3d/compare-eax-and 0/imm32/false
11064       74/jump-if-= break/disp8
11065       (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11066       e9/jump $check-mu-primitive:end/disp32
11067     }
11068     # if (op == "get") check-mu-get-stmt
11069     {
11070       (string-equal? %ecx "get")  # => eax
11071       3d/compare-eax-and 0/imm32/false
11072       74/jump-if-= break/disp8
11073       (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11074       e9/jump $check-mu-primitive:end/disp32
11075     }
11076     # if (op == "index") check-mu-index-stmt
11077     {
11078       (string-equal? %ecx "index")  # => eax
11079       3d/compare-eax-and 0/imm32/false
11080       74/jump-if-= break/disp8
11081       (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11082       e9/jump $check-mu-primitive:end/disp32
11083     }
11084     # if (op == "length") check-mu-length-stmt
11085     {
11086       (string-equal? %ecx "length")  # => eax
11087       3d/compare-eax-and 0/imm32/false
11088       74/jump-if-= break/disp8
11089       (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11090       e9/jump $check-mu-primitive:end/disp32
11091     }
11092     # if (op == "compute-offset") check-mu-compute-offset-stmt
11093     {
11094       (string-equal? %ecx "compute-offset")  # => eax
11095       3d/compare-eax-and 0/imm32/false
11096       74/jump-if-= break/disp8
11097       (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11098       e9/jump $check-mu-primitive:end/disp32
11099     }
11100     # if (op == "lookup") check-mu-lookup-stmt
11101     {
11102       (string-equal? %ecx "lookup")  # => eax
11103       3d/compare-eax-and 0/imm32/false
11104       74/jump-if-= break/disp8
11105       (check-mu-lookup-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11106       e9/jump $check-mu-primitive:end/disp32
11107     }
11108     # otherwise check-numberlike-stmt
11109     (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11110 $check-mu-primitive:end:
11111     # . restore registers
11112     59/pop-to-ecx
11113     58/pop-to-eax
11114     # . epilogue
11115     89/<- %esp 5/r32/ebp
11116     5d/pop-to-ebp
11117     c3/return
11118 
11119 # by default, Mu primitives should only operate on 'number-like' types
11120 check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11121     # . prologue
11122     55/push-ebp
11123     89/<- %ebp 4/r32/esp
11124     # . save registers
11125     50/push-eax
11126     51/push-ecx
11127     56/push-esi
11128     # esi = stmt
11129     8b/-> *(ebp+8) 6/r32/esi
11130     # var gas/ecx: int = 2
11131     b9/copy-to-ecx 2/imm32
11132     # - check at most 1 output
11133     # var output/eax: (addr stmt-var) = stmt->outputs
11134     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11135     {
11136       3d/compare-eax-and 0/imm32
11137       74/jump-if-= break/disp8
11138 $check-mu-numberlike-primitive:output:
11139       (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11140       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11141       3d/compare-eax-and 0/imm32
11142       0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
11143       # check output is in a register
11144       # --gas
11145       49/decrement-ecx
11146     }
11147     # - check first inout
11148     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11149     {
11150       3d/compare-eax-and 0/imm32
11151       0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
11152 $check-mu-numberlike-primitive:first-inout:
11153       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11154       # --gas
11155       49/decrement-ecx
11156     }
11157     # - check second inout
11158     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11159     {
11160       3d/compare-eax-and 0/imm32
11161       74/jump-if-= $check-mu-numberlike-primitive:end/disp8
11162 $check-mu-numberlike-primitive:second-inout:
11163       # is a second inout allowed?
11164       81 7/subop/compare %ecx 0/imm32
11165       0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11166 $check-mu-numberlike-primitive:second-inout-permitted:
11167       (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
11168     }
11169 $check-mu-numberlike-primitive:third-inout:
11170     # if there's a third arg, raise an error
11171     81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
11172     0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
11173 $check-mu-numberlike-primitive:end:
11174     # . restore registers
11175     5e/pop-to-esi
11176     59/pop-to-ecx
11177     58/pop-to-eax
11178     # . epilogue
11179     89/<- %esp 5/r32/ebp
11180     5d/pop-to-ebp
11181     c3/return
11182 
11183 $check-mu-numberlike-primitive:error-too-many-inouts:
11184     (write-buffered *(ebp+0x10) "fn ")
11185     8b/-> *(ebp+0xc) 0/r32/eax
11186     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11187     (write-buffered *(ebp+0x10) %eax)
11188     (write-buffered *(ebp+0x10) ": stmt ")
11189     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11190     (write-buffered *(ebp+0x10) %eax)
11191     (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
11192     (flush *(ebp+0x10))
11193     (stop *(ebp+0x14) 1)
11194     # never gets here
11195 
11196 $check-mu-numberlike-primitive:error-too-many-outputs:
11197     (write-buffered *(ebp+0x10) "fn ")
11198     8b/-> *(ebp+0xc) 0/r32/eax
11199     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11200     (write-buffered *(ebp+0x10) %eax)
11201     (write-buffered *(ebp+0x10) ": stmt ")
11202     (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
11203     (write-buffered *(ebp+0x10) %eax)
11204     (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
11205     (flush *(ebp+0x10))
11206     (stop *(ebp+0x14) 1)
11207     # never gets here
11208 
11209 check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11210     # . prologue
11211     55/push-ebp
11212     89/<- %ebp 4/r32/esp
11213     # . save registers
11214     50/push-eax
11215     56/push-esi
11216     # var t/esi: (addr type-tree) = lookup(v->value->type)
11217     8b/-> *(ebp+8) 0/r32/eax
11218     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11219     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11220     89/<- %esi 0/r32/eax
11221 $check-mu-numberlike-arg:check-literal:
11222     # if t is an int, return
11223     (is-simple-mu-type? %esi 0)  # literal => eax
11224     3d/compare-eax-and 0/imm32/false
11225     75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11226 $check-mu-numberlike-arg:check-addr:
11227     # if t is an addr and v is dereferenced, return
11228     {
11229       (is-mu-addr-type? %esi)  # => eax
11230       3d/compare-eax-and 0/imm32/false
11231       74/jump-if-= break/disp8
11232       8b/-> *(ebp+8) 0/r32/eax
11233       8b/-> *(eax+0x10) 0/r32/eax
11234       3d/compare-eax-and 0/imm32/false
11235       75/jump-if-!= $check-mu-numberlike-arg:end/disp8
11236     }
11237 $check-mu-numberlike-arg:output-checks:
11238     (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
11239 $check-mu-numberlike-arg:end:
11240     # . restore registers
11241     5e/pop-to-esi
11242     58/pop-to-eax
11243     # . epilogue
11244     89/<- %esp 5/r32/ebp
11245     5d/pop-to-ebp
11246     c3/return
11247 
11248 check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11249     # . prologue
11250     55/push-ebp
11251     89/<- %ebp 4/r32/esp
11252     # . save registers
11253     50/push-eax
11254     56/push-esi
11255     # var t/esi: (addr type-tree) = lookup(v->value->type)
11256     8b/-> *(ebp+8) 0/r32/eax
11257     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11258     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11259     89/<- %esi 0/r32/eax
11260 $check-mu-numberlike-output:check-int:
11261     # if t is an int, return
11262     (is-simple-mu-type? %esi 1)  # int => eax
11263     3d/compare-eax-and 0/imm32/false
11264     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11265 $check-mu-numberlike-output:check-boolean:
11266     # if t is a boolean, return
11267     (is-simple-mu-type? %esi 5)  # boolean => eax
11268     3d/compare-eax-and 0/imm32/false
11269     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11270 $check-mu-numberlike-output:check-byte:
11271     # if t is a byte, return
11272     (is-simple-mu-type? %esi 8)  # byte => eax
11273     3d/compare-eax-and 0/imm32/false
11274     75/jump-if-!= $check-mu-numberlike-output:end/disp8
11275     e9/jump $check-mu-numberlike-output:fail/disp32
11276 $check-mu-numberlike-output:end:
11277     # . restore registers
11278     5e/pop-to-esi
11279     58/pop-to-eax
11280     # . epilogue
11281     89/<- %esp 5/r32/ebp
11282     5d/pop-to-ebp
11283     c3/return
11284 
11285 $check-mu-numberlike-output:fail:
11286     # otherwise raise an error
11287     (write-buffered *(ebp+0x14) "fn ")
11288     8b/-> *(ebp+0x10) 0/r32/eax
11289     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11290     (write-buffered *(ebp+0x14) %eax)
11291     (write-buffered *(ebp+0x14) ": stmt ")
11292     8b/-> *(ebp+0xc) 0/r32/eax
11293     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
11294     (write-buffered *(ebp+0x14) %eax)
11295     (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
11296     (flush *(ebp+0x14))
11297     (stop *(ebp+0x18) 1)
11298     # never gets here
11299 
11300 check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11301     # . prologue
11302     55/push-ebp
11303     89/<- %ebp 4/r32/esp
11304     # . save registers
11305 $check-mu-copy-stmt:end:
11306     # . restore registers
11307     # . epilogue
11308     89/<- %esp 5/r32/ebp
11309     5d/pop-to-ebp
11310     c3/return
11311 
11312 check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11313     # . prologue
11314     55/push-ebp
11315     89/<- %ebp 4/r32/esp
11316     # . save registers
11317 $check-mu-copy-to-stmt:end:
11318     # . restore registers
11319     # . epilogue
11320     89/<- %esp 5/r32/ebp
11321     5d/pop-to-ebp
11322     c3/return
11323 
11324 check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11325     # . prologue
11326     55/push-ebp
11327     89/<- %ebp 4/r32/esp
11328     # . save registers
11329 $check-mu-compare-stmt:end:
11330     # . restore registers
11331     # . epilogue
11332     89/<- %esp 5/r32/ebp
11333     5d/pop-to-ebp
11334     c3/return
11335 
11336 check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11337     # . prologue
11338     55/push-ebp
11339     89/<- %ebp 4/r32/esp
11340     # . save registers
11341 $check-mu-address-stmt:end:
11342     # . restore registers
11343     # . epilogue
11344     89/<- %esp 5/r32/ebp
11345     5d/pop-to-ebp
11346     c3/return
11347 
11348 check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11349     # . prologue
11350     55/push-ebp
11351     89/<- %ebp 4/r32/esp
11352     # . save registers
11353     50/push-eax
11354     51/push-ecx
11355     52/push-edx
11356     53/push-ebx
11357     56/push-esi
11358     57/push-edi
11359     # esi = stmt
11360     8b/-> *(ebp+8) 6/r32/esi
11361     # - check for 0 inouts
11362     # var base/ecx: (addr var) = stmt->inouts->value
11363     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11364     3d/compare-eax-and 0/imm32/false
11365     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
11366     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11367     89/<- %ecx 0/r32/eax
11368 $check-mu-get-stmt:check-base:
11369     # - check base type
11370     # if it's an 'addr', check that it's in a register
11371     # var base-type/ebx: (addr type-tree) = lookup(base->type)
11372     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11373     89/<- %ebx 0/r32/eax
11374     {
11375       81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
11376       0f 85/jump-if-!= break/disp32
11377 $check-mu-get-stmt:base-is-compound:
11378       # if (type->left != addr) break
11379       (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
11380       (is-simple-mu-type? %eax 2)  # => eax
11381       3d/compare-eax-and 0/imm32/false
11382       74/jump-if-= break/disp8
11383 $check-mu-get-stmt:base-is-addr:
11384       # now check for register
11385       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
11386       0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
11387 $check-mu-get-stmt:base-is-addr-in-register:
11388       # type->left is now an addr; skip it
11389       (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
11390       81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
11391       0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
11392 $check-mu-get-stmt:base-is-addr-to-atom-in-register:
11393       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11394       89/<- %ebx 0/r32/eax
11395     }
11396 $check-mu-get-stmt:check-base-typeinfo:
11397     # ensure type is a container
11398     # var base-type-id/ebx: type-id = base-type->value
11399     8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
11400     (is-container? %ebx)  # => eax
11401     3d/compare-eax-and 0/imm32/false
11402     0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
11403     # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
11404     # . var container/ecx: (handle typeinfo)
11405     68/push 0/imm32
11406     68/push 0/imm32
11407     89/<- %ecx 4/r32/esp
11408     # .
11409     (find-typeinfo %ebx %ecx)
11410     (lookup *ecx *(ecx+4))  # => eax
11411     # . reclaim container
11412     81 0/subop/add %esp 8/imm32
11413     # .
11414     89/<- %edx 0/r32/eax
11415     # var offset/ecx: (addr stmt-var) = stmt->inouts->next
11416     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11417     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11418     89/<- %ecx 0/r32/eax
11419     # - check for 1 inout
11420     3d/compare-eax-and 0/imm32/false
11421     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
11422     # var offset/ecx: (addr var) = lookup(offset->value)
11423     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11424     89/<- %ecx 0/r32/eax
11425     # - check for valid field
11426     81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
11427     0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
11428     # - check for too many inouts
11429     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11430     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11431     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11432     3d/compare-eax-and 0/imm32/false
11433     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
11434     # var output/edi: (addr var) = stmt->outputs->value
11435     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11436     # - check for 0 outputs
11437     3d/compare-eax-and 0/imm32/false
11438     0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
11439     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11440     89/<- %edi 0/r32/eax
11441 $check-mu-get-stmt:check-output-type:
11442     # - check output type
11443     # must be in register
11444     (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
11445     3d/compare-eax-and 0/imm32
11446     0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
11447     # must have a non-atomic type
11448     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
11449     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
11450     0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
11451     # type must start with (addr ...)
11452     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11453     (is-simple-mu-type? %eax 2)  # => eax
11454     3d/compare-eax-and 0/imm32/false
11455     0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
11456 $check-mu-get-stmt:check-output-type-match:
11457     # payload of addr type must match 'type' definition
11458     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
11459     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
11460     # if (payload->right == null) payload = payload->left
11461     81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
11462     {
11463       75/jump-if-!= break/disp8
11464       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
11465     }
11466     89/<- %edi 0/r32/eax
11467     # . var output-name/ecx: (addr array byte)
11468     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11469     89/<- %ecx 0/r32/eax
11470     # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
11471     (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
11472     (get %eax %ecx 0x10)  # => eax
11473     # .
11474     (lookup *eax *(eax+4))  # => eax
11475     (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
11476     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11477     # .
11478     (type-equal? %edi %eax)  # => eax
11479     3d/compare-eax-and 0/imm32/false
11480     0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
11481     # - check for too many outputs
11482     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11483     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
11484     3d/compare-eax-and 0/imm32/false
11485     0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
11486 $check-mu-get-stmt:end:
11487     # . restore registers
11488     5f/pop-to-edi
11489     5e/pop-to-esi
11490     5b/pop-to-ebx
11491     5a/pop-to-edx
11492     59/pop-to-ecx
11493     58/pop-to-eax
11494     # . epilogue
11495     89/<- %esp 5/r32/ebp
11496     5d/pop-to-ebp
11497     c3/return
11498 
11499 $check-mu-get-stmt:error-too-few-inouts:
11500     (write-buffered *(ebp+0x10) "fn ")
11501     8b/-> *(ebp+0xc) 0/r32/eax
11502     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11503     (write-buffered *(ebp+0x10) %eax)
11504     (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
11505     (flush *(ebp+0x10))
11506     (stop *(ebp+0x14) 1)
11507     # never gets here
11508 
11509 $check-mu-get-stmt:error-too-many-inouts:
11510     (write-buffered *(ebp+0x10) "fn ")
11511     8b/-> *(ebp+0xc) 0/r32/eax
11512     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11513     (write-buffered *(ebp+0x10) %eax)
11514     (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
11515     (flush *(ebp+0x10))
11516     (stop *(ebp+0x14) 1)
11517     # never gets here
11518 
11519 $check-mu-get-stmt:error-too-few-outputs:
11520     (write-buffered *(ebp+0x10) "fn ")
11521     8b/-> *(ebp+0xc) 0/r32/eax
11522     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11523     (write-buffered *(ebp+0x10) %eax)
11524     (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
11525     (flush *(ebp+0x10))
11526     (stop *(ebp+0x14) 1)
11527     # never gets here
11528 
11529 $check-mu-get-stmt:error-too-many-outputs:
11530     (write-buffered *(ebp+0x10) "fn ")
11531     8b/-> *(ebp+0xc) 0/r32/eax
11532     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11533     (write-buffered *(ebp+0x10) %eax)
11534     (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
11535     (flush *(ebp+0x10))
11536     (stop *(ebp+0x14) 1)
11537     # never gets here
11538 
11539 $check-mu-get-stmt:error-bad-base:
11540     # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
11541     (write-buffered *(ebp+0x10) "fn ")
11542     8b/-> *(ebp+0xc) 0/r32/eax
11543     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11544     (write-buffered *(ebp+0x10) %eax)
11545     (write-buffered *(ebp+0x10) ": stmt get: var '")
11546     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11547     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11548     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11549     (write-buffered *(ebp+0x10) %eax)
11550     (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
11551     (flush *(ebp+0x10))
11552     (stop *(ebp+0x14) 1)
11553     # never gets here
11554 
11555 $check-mu-get-stmt:error-base-type-addr-but-not-register:
11556     (write-buffered *(ebp+0x10) "fn ")
11557     8b/-> *(ebp+0xc) 0/r32/eax
11558     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11559     (write-buffered *(ebp+0x10) %eax)
11560     (write-buffered *(ebp+0x10) ": stmt get: var '")
11561     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11562     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
11563     (lookup *eax *(eax+4))  # Var-name Var-name => eax
11564     (write-buffered *(ebp+0x10) %eax)
11565     (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
11566     (flush *(ebp+0x10))
11567     (stop *(ebp+0x14) 1)
11568     # never gets here
11569 
11570 $check-mu-get-stmt:error-bad-field:
11571     # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
11572     (write-buffered *(ebp+0x10) "fn ")
11573     8b/-> *(ebp+0xc) 0/r32/eax
11574     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11575     (write-buffered *(ebp+0x10) %eax)
11576     (write-buffered *(ebp+0x10) ": stmt get: type '")
11577     # . write(Type-id->data[tmp])
11578     bf/copy-to-edi Type-id/imm32
11579     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
11580     # .
11581     (write-buffered *(ebp+0x10) "' has no member called '")
11582     (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
11583     (write-buffered *(ebp+0x10) %eax)
11584     (write-buffered *(ebp+0x10) "'\n")
11585     (flush *(ebp+0x10))
11586     (stop *(ebp+0x14) 1)
11587     # never gets here
11588 
11589 $check-mu-get-stmt:error-output-not-in-register:
11590     (write-buffered *(ebp+0x10) "fn ")
11591     8b/-> *(ebp+0xc) 0/r32/eax
11592     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11593     (write-buffered *(ebp+0x10) %eax)
11594     (write-buffered *(ebp+0x10) ": stmt get: output '")
11595     (lookup *edi *(edi+4))  # Var-name Var-name => eax
11596     (write-buffered *(ebp+0x10) %eax)
11597     (write-buffered *(ebp+0x10) "' is not in a register\n")
11598     (flush *(ebp+0x10))
11599     (stop *(ebp+0x14) 1)
11600     # never gets here
11601 
11602 $check-mu-get-stmt:error-output-type-not-address:
11603     (write-buffered *(ebp+0x10) "fn ")
11604     8b/-> *(ebp+0xc) 0/r32/eax
11605     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11606     (write-buffered *(ebp+0x10) %eax)
11607     (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
11608     (flush *(ebp+0x10))
11609     (stop *(ebp+0x14) 1)
11610     # never gets here
11611 
11612 $check-mu-get-stmt:error-bad-output-type:
11613     (write-buffered *(ebp+0x10) "fn ")
11614     8b/-> *(ebp+0xc) 0/r32/eax
11615     (lookup *eax *(eax+4))  # Function-name Function-name => eax
11616     (write-buffered *(ebp+0x10) %eax)
11617     (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
11618     (write-buffered *(ebp+0x10) %ecx)
11619     (write-buffered *(ebp+0x10) "' of type '")
11620     bf/copy-to-edi Type-id/imm32
11621     (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
11622     (write-buffered *(ebp+0x10) "'\n")
11623     (flush *(ebp+0x10))
11624     (stop *(ebp+0x14) 1)
11625     # never gets here
11626 
11627 check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11628     # . prologue
11629     55/push-ebp
11630     89/<- %ebp 4/r32/esp
11631     # . save registers
11632 $check-mu-index-stmt:end:
11633     # . restore registers
11634     # . epilogue
11635     89/<- %esp 5/r32/ebp
11636     5d/pop-to-ebp
11637     c3/return
11638 
11639 check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11640     # . prologue
11641     55/push-ebp
11642     89/<- %ebp 4/r32/esp
11643     # . save registers
11644 $check-mu-length-stmt:end:
11645     # . restore registers
11646     # . epilogue
11647     89/<- %esp 5/r32/ebp
11648     5d/pop-to-ebp
11649     c3/return
11650 
11651 check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11652     # . prologue
11653     55/push-ebp
11654     89/<- %ebp 4/r32/esp
11655     # . save registers
11656 $check-mu-compute-offset-stmt:end:
11657     # . restore registers
11658     # . epilogue
11659     89/<- %esp 5/r32/ebp
11660     5d/pop-to-ebp
11661     c3/return
11662 
11663 check-mu-lookup-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11664     # . prologue
11665     55/push-ebp
11666     89/<- %ebp 4/r32/esp
11667     # . save registers
11668 $check-mu-lookup-stmt:end:
11669     # . restore registers
11670     # . epilogue
11671     89/<- %esp 5/r32/ebp
11672     5d/pop-to-ebp
11673     c3/return
11674 
11675 check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
11676     # . prologue
11677     55/push-ebp
11678     89/<- %ebp 4/r32/esp
11679     # . save registers
11680     50/push-eax
11681     51/push-ecx
11682     52/push-edx
11683     53/push-ebx
11684     56/push-esi
11685     57/push-edi
11686     # esi = stmt
11687     8b/-> *(ebp+8) 6/r32/esi
11688     # edi = callee
11689     8b/-> *(ebp+0xc) 7/r32/edi
11690     # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
11691     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
11692     89/<- %ecx 0/r32/eax
11693     # var expected/edx: (addr list var) = lookup(f->inouts)
11694     (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
11695     89/<- %edx 0/r32/eax
11696     {
11697 $check-mu-call:check-for-inouts:
11698       # if (inouts == 0) break
11699       81 7/subop/compare %ecx 0/imm32
11700       0f 84/jump-if-= break/disp32
11701       # if (expected == 0) error
11702       81 7/subop/compare %edx 0/imm32
11703       0f 84/jump-if-= break/disp32
11704 $check-mu-call:check-inout-type:
11705       # var v/eax: (addr v) = lookup(inouts->value)
11706       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11707       # var t/ebx: (addr type-tree) = lookup(v->type)
11708       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11709       89/<- %ebx 0/r32/eax
11710       # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
11711       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
11712       {
11713         74/jump-if-= break/disp8
11714         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
11715         89/<- %ebx 0/r32/eax
11716         # if t->right is null, t = t->left
11717         81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
11718         75/jump-if-!= break/disp8
11719         (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
11720         89/<- %ebx 0/r32/eax
11721       }
11722       # var v2/eax: (addr v) = lookup(expected->value)
11723       (lookup *edx *(edx+4))  # List-value List-value => eax
11724       # var t2/eax: (addr type-tree) = lookup(v2->type)
11725       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11726       # if (t != t2) error
11727       (type-match? %eax %ebx)  # => eax
11728       3d/compare-eax-and 0/imm32/false
11729       {
11730         0f 85/jump-if-!= break/disp32
11731         (write-buffered *(ebp+0x14) "fn ")
11732         8b/-> *(ebp+0x10) 0/r32/eax
11733         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11734         (write-buffered *(ebp+0x14) %eax)
11735         (write-buffered *(ebp+0x14) ": call ")
11736         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11737         (write-buffered *(ebp+0x14) %eax)
11738         (write-buffered *(ebp+0x14) ": type for inout '")
11739         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11740         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11741         (write-buffered *(ebp+0x14) %eax)
11742         (write-buffered *(ebp+0x14) "' is not right\n")
11743         (flush *(ebp+0x14))
11744         (stop *(ebp+0x18) 1)
11745       }
11746 $check-mu-call:continue-to-next-inout:
11747       # inouts = lookup(inouts->next)
11748       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
11749       89/<- %ecx 0/r32/eax
11750       # expected = lookup(expected->next)
11751       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
11752       89/<- %edx 0/r32/eax
11753       #
11754       e9/jump loop/disp32
11755     }
11756 $check-mu-call:check-inout-count:
11757     # if (inouts == expected) proceed
11758     39/compare %ecx 2/r32/edx
11759     {
11760       0f 84/jump-if-= break/disp32
11761       # exactly one of the two is null
11762       # if (inouts == 0) error("too many inouts")
11763       {
11764         81 7/subop/compare %ecx 0/imm32
11765         0f 84/jump-if-= break/disp32
11766         (write-buffered *(ebp+0x14) "fn ")
11767         8b/-> *(ebp+0x10) 0/r32/eax
11768         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11769         (write-buffered *(ebp+0x14) %eax)
11770         (write-buffered *(ebp+0x14) ": call ")
11771         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11772         (write-buffered *(ebp+0x14) %eax)
11773         (write-buffered *(ebp+0x14) ": too many inouts\n")
11774         (flush *(ebp+0x14))
11775         (stop *(ebp+0x18) 1)
11776       }
11777       # if (expected == 0) error("too few inouts")
11778       {
11779         81 7/subop/compare %edx 0/imm32
11780         0f 84/jump-if-= break/disp32
11781         (write-buffered *(ebp+0x14) "fn ")
11782         8b/-> *(ebp+0x10) 0/r32/eax
11783         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11784         (write-buffered *(ebp+0x14) %eax)
11785         (write-buffered *(ebp+0x14) ": call ")
11786         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11787         (write-buffered *(ebp+0x14) %eax)
11788         (write-buffered *(ebp+0x14) ": too few inouts\n")
11789         (flush *(ebp+0x14))
11790         (stop *(ebp+0x18) 1)
11791       }
11792     }
11793 $check-mu-call:check-outputs:
11794     # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
11795     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
11796     89/<- %ecx 0/r32/eax
11797     # var expected/edx: (addr list var) = lookup(f->outputs)
11798     (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
11799     89/<- %edx 0/r32/eax
11800     {
11801 $check-mu-call:check-for-outputs:
11802       # if (outputs == 0) break
11803       81 7/subop/compare %ecx 0/imm32
11804       0f 84/jump-if-= break/disp32
11805       # if (expected == 0) error
11806       81 7/subop/compare %edx 0/imm32
11807       0f 84/jump-if-= break/disp32
11808 $check-mu-call:check-output-type:
11809       # var v/eax: (addr v) = lookup(outputs->value)
11810       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11811       # var t/ebx: (addr type-tree) = lookup(v->type)
11812       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11813       89/<- %ebx 0/r32/eax
11814       # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
11815       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
11816       {
11817         74/jump-if-= break/disp8
11818         (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
11819         89/<- %ebx 0/r32/eax
11820       }
11821       # var v2/eax: (addr v) = lookup(expected->value)
11822       (lookup *edx *(edx+4))  # List-value List-value => eax
11823       # var t2/eax: (addr type-tree) = lookup(v2->type)
11824       (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
11825       # if (t != t2) error
11826       (type-equal? %eax %ebx)  # => eax
11827       3d/compare-eax-and 0/imm32/false
11828       {
11829         0f 85/jump-if-!= break/disp32
11830         (write-buffered *(ebp+0x14) "fn ")
11831         8b/-> *(ebp+0x10) 0/r32/eax
11832         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11833         (write-buffered *(ebp+0x14) %eax)
11834         (write-buffered *(ebp+0x14) ": call ")
11835         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11836         (write-buffered *(ebp+0x14) %eax)
11837         (write-buffered *(ebp+0x14) ": type for output '")
11838         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11839         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11840         (write-buffered *(ebp+0x14) %eax)
11841         (write-buffered *(ebp+0x14) "' is not right\n")
11842         (flush *(ebp+0x14))
11843         (stop *(ebp+0x18) 1)
11844       }
11845 $check-mu-call:check-output-register:
11846       # var v/eax: (addr v) = lookup(outputs->value)
11847       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11848       # var r/ebx: (addr array byte) = lookup(v->register)
11849       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
11850       89/<- %ebx 0/r32/eax
11851       # var v2/eax: (addr v) = lookup(expected->value)
11852       (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
11853       # var r2/eax: (addr array byte) = lookup(v2->register)
11854       (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
11855       # if (r != r2) error
11856       (string-equal? %eax %ebx)  # => eax
11857       3d/compare-eax-and 0/imm32/false
11858       {
11859         0f 85/jump-if-!= break/disp32
11860         (write-buffered *(ebp+0x14) "fn ")
11861         8b/-> *(ebp+0x10) 0/r32/eax
11862         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11863         (write-buffered *(ebp+0x14) %eax)
11864         (write-buffered *(ebp+0x14) ": call ")
11865         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11866         (write-buffered *(ebp+0x14) %eax)
11867         (write-buffered *(ebp+0x14) ": register for output '")
11868         (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
11869         (lookup *eax *(eax+4))  # Var-name Var-name => eax
11870         (write-buffered *(ebp+0x14) %eax)
11871         (write-buffered *(ebp+0x14) "' is not right\n")
11872         (flush *(ebp+0x14))
11873         (stop *(ebp+0x18) 1)
11874       }
11875 $check-mu-call:continue-to-next-output:
11876       # outputs = lookup(outputs->next)
11877       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
11878       89/<- %ecx 0/r32/eax
11879       # expected = lookup(expected->next)
11880       (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
11881       89/<- %edx 0/r32/eax
11882       #
11883       e9/jump loop/disp32
11884     }
11885 $check-mu-call:check-output-count:
11886     # if (outputs == expected) proceed
11887     39/compare %ecx 2/r32/edx
11888     {
11889       0f 84/jump-if-= break/disp32
11890       # exactly one of the two is null
11891       # if (outputs == 0) error("too many outputs")
11892       {
11893         81 7/subop/compare %ecx 0/imm32
11894         0f 84/jump-if-= break/disp32
11895         (write-buffered *(ebp+0x14) "fn ")
11896         8b/-> *(ebp+0x10) 0/r32/eax
11897         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11898         (write-buffered *(ebp+0x14) %eax)
11899         (write-buffered *(ebp+0x14) ": call ")
11900         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11901         (write-buffered *(ebp+0x14) %eax)
11902         (write-buffered *(ebp+0x14) ": too many outputs\n")
11903         (flush *(ebp+0x14))
11904         (stop *(ebp+0x18) 1)
11905       }
11906       # if (expected == 0) error("too few outputs")
11907       {
11908         81 7/subop/compare %edx 0/imm32
11909         0f 84/jump-if-= break/disp32
11910         (write-buffered *(ebp+0x14) "fn ")
11911         8b/-> *(ebp+0x10) 0/r32/eax
11912         (lookup *eax *(eax+4))  # Function-name Function-name => eax
11913         (write-buffered *(ebp+0x14) %eax)
11914         (write-buffered *(ebp+0x14) ": call ")
11915         (lookup *edi *(edi+4))  # Function-name Function-name => eax
11916         (write-buffered *(ebp+0x14) %eax)
11917         (write-buffered *(ebp+0x14) ": too few outputs\n")
11918         (flush *(ebp+0x14))
11919         (stop *(ebp+0x18) 1)
11920       }
11921     }
11922 $check-mu-call:end:
11923     # . restore registers
11924     5f/pop-to-edi
11925     5e/pop-to-esi
11926     5b/pop-to-ebx
11927     5a/pop-to-edx
11928     59/pop-to-ecx
11929     58/pop-to-eax
11930     # . epilogue
11931     89/<- %esp 5/r32/ebp
11932     5d/pop-to-ebp
11933     c3/return
11934 
11935 # like type-equal? but takes literals into account
11936 type-match?:  # def: (addr type-tree), call: (addr type-tree) -> result/eax: boolean
11937     # . prologue
11938     55/push-ebp
11939     89/<- %ebp 4/r32/esp
11940     # if (call == literal) return true  # TODO: more precise
11941     (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
11942     3d/compare-eax-and 0/imm32/false
11943     b8/copy-to-eax 1/imm32/true
11944     75/jump-if-!= $type-match?:end/disp8
11945 $type-match?:baseline:
11946     # otherwise fall back
11947     (type-equal? *(ebp+8) *(ebp+0xc))  # => eax
11948 $type-match?:end:
11949     # . epilogue
11950     89/<- %esp 5/r32/ebp
11951     5d/pop-to-ebp
11952     c3/return
11953 
11954 size-of:  # v: (addr var) -> result/eax: int
11955     # . prologue
11956     55/push-ebp
11957     89/<- %ebp 4/r32/esp
11958     # . save registers
11959     51/push-ecx
11960     # var t/ecx: (addr type-tree) = lookup(v->type)
11961     8b/-> *(ebp+8) 1/r32/ecx
11962 #?     (write-buffered Stderr "size-of ")
11963 #?     (write-int32-hex-buffered Stderr %ecx)
11964 #?     (write-buffered Stderr Newline)
11965 #?     (write-buffered Stderr "type allocid: ")
11966 #?     (write-int32-hex-buffered Stderr *(ecx+8))
11967 #?     (write-buffered Stderr Newline)
11968 #?     (flush Stderr)
11969     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
11970     89/<- %ecx 0/r32/eax
11971     # if is-mu-array?(t) return size-of-array(t)
11972     {
11973       (is-mu-array? %ecx)  # => eax
11974       3d/compare-eax-and 0/imm32/false
11975       74/jump-if-= break/disp8
11976       (size-of-array %ecx)  # => eax
11977       eb/jump $size-of:end/disp8
11978     }
11979     # if (!t->is-atom?) t = lookup(t->left)
11980     {
11981       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
11982       75/jump-if-!= break/disp8
11983       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
11984       89/<- %ecx 0/r32/eax
11985     }
11986     # TODO: assert t->is-atom?
11987     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
11988 $size-of:end:
11989     # . restore registers
11990     59/pop-to-ecx
11991     # . epilogue
11992     89/<- %esp 5/r32/ebp
11993     5d/pop-to-ebp
11994     c3/return
11995 
11996 size-of-deref:  # v: (addr var) -> result/eax: int
11997     # . prologue
11998     55/push-ebp
11999     89/<- %ebp 4/r32/esp
12000     # . save registers
12001     51/push-ecx
12002     # var t/ecx: (addr type-tree) = lookup(v->type)
12003     8b/-> *(ebp+8) 1/r32/ecx
12004     (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
12005     89/<- %ecx 0/r32/eax
12006     # TODO: assert(t is an addr)
12007     # t = lookup(t->right)
12008     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12009     89/<- %ecx 0/r32/eax
12010     # if is-mu-array?(t) return size-of-array(t)
12011     {
12012       (is-mu-array? %ecx)  # => eax
12013       3d/compare-eax-and 0/imm32/false
12014       74/jump-if-= break/disp8
12015       (size-of-array %ecx)  # => eax
12016       eb/jump $size-of:end/disp8
12017     }
12018     # if (!t->is-atom?) t = lookup(t->left)
12019     {
12020       81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12021       75/jump-if-!= break/disp8
12022       (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12023       89/<- %ecx 0/r32/eax
12024     }
12025     # TODO: assert t->is-atom?
12026     (size-of-type-id *(ecx+4))  # Type-tree-value => eax
12027 $size-of-deref:end:
12028     # . restore registers
12029     59/pop-to-ecx
12030     # . epilogue
12031     89/<- %esp 5/r32/ebp
12032     5d/pop-to-ebp
12033     c3/return
12034 
12035 is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
12036     # . prologue
12037     55/push-ebp
12038     89/<- %ebp 4/r32/esp
12039     # . save registers
12040     51/push-ecx
12041     # ecx = t
12042     8b/-> *(ebp+8) 1/r32/ecx
12043     # if t->is-atom?, return false
12044     81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
12045     75/jump-if-!= $is-mu-array?:return-false/disp8
12046     # if !t->left->is-atom?, return false
12047     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12048     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
12049     74/jump-if-= $is-mu-array?:return-false/disp8
12050     # return t->left->value == array
12051     81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
12052     0f 94/set-if-= %al
12053     81 4/subop/and %eax 0xff/imm32
12054     eb/jump $is-mu-array?:end/disp8
12055 $is-mu-array?:return-false:
12056     b8/copy-to-eax 0/imm32/false
12057 $is-mu-array?:end:
12058     # . restore registers
12059     59/pop-to-ecx
12060     # . epilogue
12061     89/<- %esp 5/r32/ebp
12062     5d/pop-to-ebp
12063     c3/return
12064 
12065 size-of-array:  # a: (addr type-tree) -> result/eax: int
12066     # . prologue
12067     55/push-ebp
12068     89/<- %ebp 4/r32/esp
12069     # . save registers
12070     51/push-ecx
12071     52/push-edx
12072     #
12073     8b/-> *(ebp+8) 1/r32/ecx
12074     # TODO: assert that a->left is 'array'
12075     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12076     89/<- %ecx 0/r32/eax
12077     # var elem-type/edx: type-id = a->right->left->value
12078     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12079     8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
12080     # TODO: assert that a->right->right->left->value == size
12081     # var array-size/ecx: int = a->right->right->left->value-size
12082     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12083     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
12084     8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
12085     # return array-size * size-of(elem-type)
12086     (size-of-type-id-as-array-element %edx)  # => eax
12087     f7 4/subop/multiply-into-eax %ecx
12088     05/add-to-eax 4/imm32  # for array size
12089 $size-of-array:end:
12090     # . restore registers
12091     5a/pop-to-edx
12092     59/pop-to-ecx
12093     # . epilogue
12094     89/<- %esp 5/r32/ebp
12095     5d/pop-to-ebp
12096     c3/return
12097 
12098 size-of-type-id:  # t: type-id -> result/eax: int
12099     # . prologue
12100     55/push-ebp
12101     89/<- %ebp 4/r32/esp
12102     # . save registers
12103     51/push-ecx
12104     # var out/ecx: (handle typeinfo)
12105     68/push 0/imm32
12106     68/push 0/imm32
12107     89/<- %ecx 4/r32/esp
12108     # eax = t
12109     8b/-> *(ebp+8) 0/r32/eax
12110     # if t is a literal, return 0
12111     3d/compare-eax-and 0/imm32
12112     0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
12113     # if t is a byte, return 4 (because we don't really support non-multiples of 4)
12114     3d/compare-eax-and 8/imm32/byte
12115     {
12116       75/jump-if-!= break/disp8
12117       b8/copy-to-eax 4/imm32
12118       eb/jump $size-of-type-id:end/disp8
12119     }
12120     # if t is a handle, return 8
12121     3d/compare-eax-and 4/imm32/handle
12122     {
12123       75/jump-if-!= break/disp8
12124       b8/copy-to-eax 8/imm32
12125       eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
12126     }
12127     # if t is a user-defined type, return its size
12128     # TODO: support non-atom type
12129     (find-typeinfo %eax %ecx)
12130     {
12131       81 7/subop/compare *ecx 0/imm32
12132       74/jump-if-= break/disp8
12133 $size-of-type-id:user-defined:
12134       (lookup *ecx *(ecx+4))  # => eax
12135       8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
12136       eb/jump $size-of-type-id:end/disp8
12137     }
12138     # otherwise return the word size
12139     b8/copy-to-eax 4/imm32
12140 $size-of-type-id:end:
12141     # . reclaim locals
12142     81 0/subop/add %esp 8/imm32
12143     # . restore registers
12144     59/pop-to-ecx
12145     # . epilogue
12146     89/<- %esp 5/r32/ebp
12147     5d/pop-to-ebp
12148     c3/return
12149 
12150 type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
12151     # . prologue
12152     55/push-ebp
12153     89/<- %ebp 4/r32/esp
12154     # . save registers
12155     51/push-ecx
12156     52/push-edx
12157     53/push-ebx
12158     # ecx = a
12159     8b/-> *(ebp+8) 1/r32/ecx
12160     # edx = b
12161     8b/-> *(ebp+0xc) 2/r32/edx
12162 $type-equal?:compare-addr:
12163     # if (a == b) return true
12164     8b/-> %ecx 0/r32/eax  # Var-type
12165     39/compare %edx 0/r32/eax  # Var-type
12166     b8/copy-to-eax 1/imm32/true
12167     0f 84/jump-if-= $type-equal?:end/disp32
12168 $type-equal?:compare-atom-state:
12169     # if (a->is-atom? != b->is-atom?) return false
12170     8b/-> *ecx 3/r32/ebx  # Type-tree-value
12171     39/compare *edx 3/r32/ebx  # Type-tree-value
12172     b8/copy-to-eax 0/imm32/false
12173     0f 85/jump-if-!= $type-equal?:end/disp32
12174     # if a->is-atom? return (a->value == b->value)
12175     {
12176 $type-equal?:check-atom:
12177       81 7/subop/compare %ebx 0/imm32/false
12178       74/jump-if-= break/disp8
12179 $type-equal?:is-atom:
12180       8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
12181       39/compare *(edx+4) 0/r32/eax  # Type-tree-value
12182       0f 94/set-if-= %al
12183       81 4/subop/and %eax 0xff/imm32
12184       e9/jump $type-equal?:end/disp32
12185     }
12186 $type-equal?:check-left:
12187     # if (!type-equal?(a->left, b->left)) return false
12188     (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
12189     89/<- %ebx 0/r32/eax
12190     (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
12191     (type-equal? %eax %ebx)  # => eax
12192     3d/compare-eax-and 0/imm32/false
12193     74/jump-if-= $type-equal?:end/disp8
12194 $type-equal?:check-right:
12195     # return type-equal?(a->right, b->right)
12196     (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
12197     89/<- %ebx 0/r32/eax
12198     (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
12199     (type-equal? %eax %ebx)  # => eax
12200 $type-equal?:end:
12201     # . restore registers
12202     5b/pop-to-ebx
12203     5a/pop-to-edx
12204     59/pop-to-ecx
12205     # . epilogue
12206     89/<- %esp 5/r32/ebp
12207     5d/pop-to-ebp
12208     c3/return
12209 
12210 #######################################################
12211 # Code-generation
12212 #######################################################
12213 
12214 == data
12215 
12216 # Global state added to each var record when performing code-generation.
12217 Curr-local-stack-offset:  # (addr int)
12218     0/imm32
12219 
12220 == code
12221 
12222 emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
12223     # . prologue
12224     55/push-ebp
12225     89/<- %ebp 4/r32/esp
12226     # . save registers
12227     50/push-eax
12228     # var curr/eax: (addr function) = *Program->functions
12229     (lookup *_Program-functions *_Program-functions->payload)  # => eax
12230     {
12231       # if (curr == null) break
12232       3d/compare-eax-and 0/imm32
12233       0f 84/jump-if-= break/disp32
12234       (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
12235       # curr = lookup(curr->next)
12236       (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
12237       e9/jump loop/disp32
12238     }
12239 $emit-subx:end:
12240     # . restore registers
12241     58/pop-to-eax
12242     # . epilogue
12243     89/<- %esp 5/r32/ebp
12244     5d/pop-to-ebp
12245     c3/return
12246 
12247 emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12248     # . prologue
12249     55/push-ebp
12250     89/<- %ebp 4/r32/esp
12251     # some preprocessing
12252     (populate-mu-type-offsets-in-inouts *(ebp+0xc))
12253     # . save registers
12254     50/push-eax
12255     51/push-ecx
12256     52/push-edx
12257     # initialize some global state
12258     c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
12259     c7 0/subop/copy *Curr-local-stack-offset 0/imm32
12260     # ecx = f
12261     8b/-> *(ebp+0xc) 1/r32/ecx
12262     # var vars/edx: (stack (addr var) 256)
12263     81 5/subop/subtract %esp 0xc00/imm32
12264     68/push 0xc00/imm32/size
12265     68/push 0/imm32/top
12266     89/<- %edx 4/r32/esp
12267     # var name/eax: (addr array byte) = lookup(f->name)
12268     (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
12269     #
12270     (write-buffered *(ebp+8) %eax)
12271     (write-buffered *(ebp+8) ":\n")
12272     (emit-subx-prologue *(ebp+8))
12273     # var body/eax: (addr block) = lookup(f->body)
12274     (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
12275     #
12276     (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
12277     (emit-subx-epilogue *(ebp+8))
12278     # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
12279     # been cleaned up
12280 $emit-subx-function:end:
12281     # . reclaim locals
12282     81 0/subop/add %esp 0xc08/imm32
12283     # . restore registers
12284     5a/pop-to-edx
12285     59/pop-to-ecx
12286     58/pop-to-eax
12287     # . epilogue
12288     89/<- %esp 5/r32/ebp
12289     5d/pop-to-ebp
12290     c3/return
12291 
12292 populate-mu-type-offsets-in-inouts:  # f: (addr function)
12293     # . prologue
12294     55/push-ebp
12295     89/<- %ebp 4/r32/esp
12296     # . save registers
12297     50/push-eax
12298     51/push-ecx
12299     52/push-edx
12300     53/push-ebx
12301     57/push-edi
12302     # var next-offset/edx: int = 8
12303     ba/copy-to-edx 8/imm32
12304     # var curr/ecx: (addr list var) = lookup(f->inouts)
12305     8b/-> *(ebp+8) 1/r32/ecx
12306     (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
12307     89/<- %ecx 0/r32/eax
12308     {
12309 $populate-mu-type-offsets-in-inouts:loop:
12310       81 7/subop/compare %ecx 0/imm32
12311       74/jump-if-= break/disp8
12312       # var v/ebx: (addr var) = lookup(curr->value)
12313       (lookup *ecx *(ecx+4))  # List-value List-value => eax
12314       89/<- %ebx 0/r32/eax
12315 #?       (lookup *ebx *(ebx+4))
12316 #?       (write-buffered Stderr "setting offset of fn inout ")
12317 #?       (write-buffered Stderr %eax)
12318 #?       (write-buffered Stderr "@")
12319 #?       (write-int32-hex-buffered Stderr %ebx)
12320 #?       (write-buffered Stderr " to ")
12321 #?       (write-int32-hex-buffered Stderr %edx)
12322 #?       (write-buffered Stderr Newline)
12323 #?       (flush Stderr)
12324       # v->offset = next-offset
12325       89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
12326       # next-offset += size-of(v)
12327       (size-of %ebx)  # => eax
12328       01/add-to %edx 0/r32/eax
12329       # curr = lookup(curr->next)
12330       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
12331       89/<- %ecx 0/r32/eax
12332       #
12333       eb/jump loop/disp8
12334     }
12335 $populate-mu-type-offsets-in-inouts:end:
12336     # . restore registers
12337     5f/pop-to-edi
12338     5b/pop-to-ebx
12339     5a/pop-to-edx
12340     59/pop-to-ecx
12341     58/pop-to-eax
12342     # . epilogue
12343     89/<- %esp 5/r32/ebp
12344     5d/pop-to-ebp
12345     c3/return
12346 
12347 emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12348     # . prologue
12349     55/push-ebp
12350     89/<- %ebp 4/r32/esp
12351     # . save registers
12352     50/push-eax
12353     51/push-ecx
12354     53/push-ebx
12355     56/push-esi
12356     # esi = stmts
12357     8b/-> *(ebp+0xc) 6/r32/esi
12358     #
12359     {
12360 $emit-subx-stmt-list:loop:
12361       81 7/subop/compare %esi 0/imm32
12362       0f 84/jump-if-= break/disp32
12363       # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
12364       (lookup *esi *(esi+4))  # List-value List-value => eax
12365       89/<- %ecx 0/r32/eax
12366       {
12367 $emit-subx-stmt-list:check-for-block:
12368         81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
12369         75/jump-if-!= break/disp8
12370 $emit-subx-stmt-list:block:
12371         (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
12372       }
12373       {
12374 $emit-subx-stmt-list:check-for-stmt:
12375         81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
12376         0f 85/jump-if-!= break/disp32
12377 $emit-subx-stmt-list:stmt1:
12378         {
12379           (is-mu-branch? %ecx)  # => eax
12380           3d/compare-eax-and 0/imm32/false
12381           0f 84/jump-if-= break/disp32
12382 $emit-subx-stmt-list:branch-stmt:
12383 +-- 27 lines: # unconditional loops -----------------------------------------------------------------------------------------------------------------------------------------------------
12410 +-- 16 lines: # unconditional breaks ----------------------------------------------------------------------------------------------------------------------------------------------------
12426 +-- 38 lines: # simple conditional branches without a target ----------------------------------------------------------------------------------------------------------------------------
12464 +-- 19 lines: # conditional branches with an explicit target ----------------------------------------------------------------------------------------------------------------------------
12483         }
12484 $emit-subx-stmt-list:1-to-1:
12485         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
12486         e9/jump $emit-subx-stmt-list:continue/disp32
12487       }
12488       {
12489 $emit-subx-stmt-list:check-for-var-def:
12490         81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
12491         75/jump-if-!= break/disp8
12492 $emit-subx-stmt-list:var-def:
12493         (emit-subx-var-def *(ebp+8) %ecx)
12494         (push *(ebp+0x10) *(ecx+4))  # Vardef-var
12495         (push *(ebp+0x10) *(ecx+8))  # Vardef-var
12496         (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
12497         #
12498         eb/jump $emit-subx-stmt-list:continue/disp8
12499       }
12500       {
12501 $emit-subx-stmt-list:check-for-reg-var-def:
12502         81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
12503         0f 85/jump-if-!= break/disp32
12504 $emit-subx-stmt-list:reg-var-def:
12505         # TODO: ensure that there's exactly one output
12506         (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
12507         # emit the instruction as usual
12508         (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
12509         #
12510         eb/jump $emit-subx-stmt-list:continue/disp8
12511       }
12512 $emit-subx-stmt-list:continue:
12513       # TODO: raise an error on unrecognized Stmt-tag
12514       (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
12515       89/<- %esi 0/r32/eax
12516       e9/jump loop/disp32
12517     }
12518 $emit-subx-stmt-list:emit-cleanup:
12519     (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
12520 $emit-subx-stmt-list:clean-up:
12521     (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
12522 $emit-subx-stmt-list:end:
12523     # . restore registers
12524     5e/pop-to-esi
12525     5b/pop-to-ebx
12526     59/pop-to-ecx
12527     58/pop-to-eax
12528     # . epilogue
12529     89/<- %esp 5/r32/ebp
12530     5d/pop-to-ebp
12531     c3/return
12532 
12533 # 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
12534 push-output-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var)), later-stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
12535     # . prologue
12536     55/push-ebp
12537     89/<- %ebp 4/r32/esp
12538     # . save registers
12539     50/push-eax
12540     51/push-ecx
12541     52/push-edx
12542     # ecx = stmt
12543     8b/-> *(ebp+0xc) 1/r32/ecx
12544     # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
12545     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
12546     # TODO: assert !sv->is-deref?
12547     # var v/ecx: (addr var) = lookup(sv->value)
12548     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12549     89/<- %ecx 0/r32/eax
12550     # v->block-depth = *Curr-block-depth
12551     8b/-> *Curr-block-depth 0/r32/eax
12552     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
12553 #?     (write-buffered Stderr "var ")
12554 #?     (lookup *ecx *(ecx+4))
12555 #?     (write-buffered Stderr %eax)
12556 #?     (write-buffered Stderr " at depth ")
12557 #?     (write-int32-hex-buffered Stderr *(ecx+0x10))
12558 #?     (write-buffered Stderr Newline)
12559 #?     (flush Stderr)
12560     # ensure that v is in a register
12561     81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
12562     0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
12563     # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
12564     (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
12565     89/<- %edx 0/r32/eax
12566     3d/compare-eax-and 0/imm32/false
12567     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
12568     (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
12569     89/<- %edx 0/r32/eax
12570     # check emit-spill?
12571     3d/compare-eax-and 0/imm32/false
12572     0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
12573     # TODO: assert(size-of(output) == 4)
12574     # *Curr-local-stack-offset -= 4
12575     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
12576     # emit spill
12577     (emit-indent *(ebp+8) *Curr-block-depth)
12578     (write-buffered *(ebp+8) "ff 6/subop/push %")
12579     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
12580     (write-buffered *(ebp+8) %eax)
12581     (write-buffered *(ebp+8) Newline)
12582 $push-output-and-maybe-emit-spill:push:
12583     8b/-> *(ebp+0xc) 1/r32/ecx
12584     (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
12585     # push(vars, {sv->value, emit-spill?})
12586     (push *(ebp+0x10) *eax)  # Stmt-var-value
12587     (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
12588     (push *(ebp+0x10) %edx)
12589 $push-output-and-maybe-emit-spill:end:
12590     # . restore registers
12591     5a/pop-to-edx
12592     59/pop-to-ecx
12593     58/pop-to-eax
12594     # . epilogue
12595     89/<- %esp 5/r32/ebp
12596     5d/pop-to-ebp
12597     c3/return
12598 
12599 $push-output-and-maybe-emit-spill:abort:
12600     # error("var '" var->name "' initialized from an instruction must live in a register\n")
12601     (write-buffered *(ebp+0x1c) "var '")
12602     (write-buffered *(ebp+0x1c) *eax)  # Var-name
12603     (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
12604     (flush *(ebp+0x1c))
12605     (stop *(ebp+0x20) 1)
12606     # never gets here
12607 
12608 emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
12609     # . prologue
12610     55/push-ebp
12611     89/<- %ebp 4/r32/esp
12612     # . save registers
12613     50/push-eax
12614     51/push-ecx
12615     # ecx = stmt
12616     8b/-> *(ebp+0xc) 1/r32/ecx
12617     # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
12618     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
12619     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
12620     (lookup *eax *(eax+4))  # Var-name Var-name => eax
12621     # clean up until target block
12622     (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
12623     # emit jump to target block
12624     (emit-indent *(ebp+8) *Curr-block-depth)
12625     (write-buffered *(ebp+8) "e9/jump ")
12626     (write-buffered *(ebp+8) %eax)
12627     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
12628     (string-starts-with? %eax "break")
12629     3d/compare-eax-and 0/imm32/false
12630     {
12631       74/jump-if-= break/disp8
12632       (write-buffered *(ebp+8) ":break/disp32\n")
12633     }
12634     3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
12635     {
12636       75/jump-if-!= break/disp8
12637       (write-buffered *(ebp+8) ":loop/disp32\n")
12638     }
12639 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
12640     # . restore registers
12641     59/pop-to-ecx
12642     58/pop-to-eax
12643     # . epilogue
12644     89/<- %esp 5/r32/ebp
12645     5d/pop-to-ebp
12646     c3/return
12647 
12648 is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
12649     # . prologue
12650     55/push-ebp
12651     89/<- %ebp 4/r32/esp
12652     # . save registers
12653     51/push-ecx
12654     # ecx = lookup(stmt->operation)
12655     8b/-> *(ebp+8) 1/r32/ecx
12656     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
12657     89/<- %ecx 0/r32/eax
12658     # if (stmt->operation starts with "loop") return true
12659     (string-starts-with? %ecx "loop")  # => eax
12660     3d/compare-eax-and 0/imm32/false
12661     75/jump-if-not-equal $is-mu-branch?:end/disp8
12662     # otherwise return (stmt->operation starts with "break")
12663     (string-starts-with? %ecx "break")  # => eax
12664 $is-mu-branch?:end:
12665     # . restore registers
12666     59/pop-to-ecx
12667     # . epilogue
12668     89/<- %esp 5/r32/ebp
12669     5d/pop-to-ebp
12670     c3/return
12671 
12672 emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
12673     # . prologue
12674     55/push-ebp
12675     89/<- %ebp 4/r32/esp
12676     # . save registers
12677     50/push-eax
12678     # eax = stmt
12679     8b/-> *(ebp+0xc) 0/r32/eax
12680     #
12681     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
12682     (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
12683     (emit-indent *(ebp+8) *Curr-block-depth)
12684     (lookup *eax *(eax+4))  # => eax
12685     (write-buffered *(ebp+8) %eax)
12686     (write-buffered *(ebp+8) " break/disp32\n")
12687 $emit-reverse-break:end:
12688     # . restore registers
12689     58/pop-to-eax
12690     # . epilogue
12691     89/<- %esp 5/r32/ebp
12692     5d/pop-to-ebp
12693     c3/return
12694 
12695 == data
12696 
12697 # Table from Mu branch instructions to the reverse SubX opcodes for them.
12698 Reverse-branch:  # (table (handle array byte) (handle array byte))
12699   # a table is a stream
12700   0x140/imm32/write
12701   0/imm32/read
12702   0x140/imm32/size
12703   # data
12704   0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
12705   0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
12706   0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
12707   0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
12708   0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
12709   0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
12710   0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
12711   0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
12712   0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12713   0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12714   0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
12715   0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
12716   0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
12717   0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
12718   0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
12719   0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
12720   0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12721   0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
12722   0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
12723   0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
12724 
12725 == code
12726 
12727 emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
12728     # . prologue
12729     55/push-ebp
12730     89/<- %ebp 4/r32/esp
12731     # . save registers
12732     50/push-eax
12733     51/push-ecx
12734     52/push-edx
12735     53/push-ebx
12736     56/push-esi
12737     # ecx = vars
12738     8b/-> *(ebp+0xc) 1/r32/ecx
12739     # var eax: int = vars->top
12740     8b/-> *ecx 0/r32/eax
12741     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
12742     8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
12743     # var min/ecx: (addr handle var) = vars->data
12744     8d/copy-address *(ecx+8) 1/r32/ecx
12745     # edx = depth
12746     8b/-> *(ebp+0x10) 2/r32/edx
12747     {
12748 $emit-unconditional-jump-to-depth:loop:
12749       # if (curr < min) break
12750       39/compare %esi 1/r32/ecx
12751       0f 82/jump-if-addr< break/disp32
12752       # var v/ebx: (addr var) = lookup(*curr)
12753       (lookup *esi *(esi+4))  # => eax
12754       89/<- %ebx 0/r32/eax
12755       # if (v->block-depth < until-block-depth) break
12756       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12757       0f 8c/jump-if-< break/disp32
12758       {
12759 $emit-unconditional-jump-to-depth:check:
12760         # if v->block-depth != until-block-depth, continue
12761         39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12762         0f 85/jump-if-!= break/disp32
12763 $emit-unconditional-jump-to-depth:depth-found:
12764         # if v is not a literal, continue
12765         (size-of %ebx)  # => eax
12766         3d/compare-eax-and 0/imm32
12767         0f 85/jump-if-!= break/disp32
12768 $emit-unconditional-jump-to-depth:label-found:
12769         # emit unconditional jump, then return
12770         (emit-indent *(ebp+8) *Curr-block-depth)
12771         (write-buffered *(ebp+8) "e9/jump ")
12772         (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
12773         (write-buffered *(ebp+8) %eax)
12774         (write-buffered *(ebp+8) ":")
12775         (write-buffered *(ebp+8) *(ebp+0x14))
12776         (write-buffered *(ebp+8) "/disp32\n")
12777         eb/jump $emit-unconditional-jump-to-depth:end/disp8
12778       }
12779       # curr -= 12
12780       81 5/subop/subtract %esi 0xc/imm32
12781       e9/jump loop/disp32
12782     }
12783     # TODO: error if no label at 'depth' was found
12784 $emit-unconditional-jump-to-depth:end:
12785     # . restore registers
12786     5e/pop-to-esi
12787     5b/pop-to-ebx
12788     5a/pop-to-edx
12789     59/pop-to-ecx
12790     58/pop-to-eax
12791     # . epilogue
12792     89/<- %esp 5/r32/ebp
12793     5d/pop-to-ebp
12794     c3/return
12795 
12796 # emit clean-up code for 'vars' until some block depth
12797 # doesn't actually modify 'vars' so we need traverse manually inside the stack
12798 emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
12799     # . prologue
12800     55/push-ebp
12801     89/<- %ebp 4/r32/esp
12802     # . save registers
12803     50/push-eax
12804     51/push-ecx
12805     52/push-edx
12806     53/push-ebx
12807     56/push-esi
12808 #?     (write-buffered Stderr "--- cleanup\n")
12809 #?     (flush Stderr)
12810     # ecx = vars
12811     8b/-> *(ebp+0xc) 1/r32/ecx
12812     # var esi: int = vars->top
12813     8b/-> *ecx 6/r32/esi
12814     # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
12815     8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
12816     # var min/ecx: (addr handle var) = vars->data
12817     81 0/subop/add %ecx 8/imm32
12818     # edx = until-block-depth
12819     8b/-> *(ebp+0x10) 2/r32/edx
12820     {
12821 $emit-cleanup-code-until-depth:loop:
12822       # if (curr < min) break
12823       39/compare %esi 1/r32/ecx
12824       0f 82/jump-if-addr< break/disp32
12825       # var v/ebx: (addr var) = lookup(*curr)
12826       (lookup *esi *(esi+4))  # => eax
12827       89/<- %ebx 0/r32/eax
12828 #?       (lookup *ebx *(ebx+4))  # Var-name
12829 #?       (write-buffered Stderr "var ")
12830 #?       (write-buffered Stderr %eax)
12831 #?       (write-buffered Stderr Newline)
12832 #?       (flush Stderr)
12833       # if (v->block-depth < until-block-depth) break
12834       39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
12835       0f 8c/jump-if-< break/disp32
12836       # if v is in a register
12837       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
12838       {
12839         0f 84/jump-if-= break/disp32
12840         {
12841 $emit-cleanup-code-until-depth:check-for-previous-spill:
12842           8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
12843           3d/compare-eax-and 0/imm32/false
12844           74/jump-if-= break/disp8
12845 $emit-cleanup-code-until-depth:reclaim-var-in-register:
12846           (emit-indent *(ebp+8) *Curr-block-depth)
12847           (write-buffered *(ebp+8) "8f 0/subop/pop %")
12848           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
12849           (write-buffered *(ebp+8) %eax)
12850           (write-buffered *(ebp+8) Newline)
12851         }
12852         eb/jump $emit-cleanup-code-until-depth:continue/disp8
12853       }
12854       # otherwise v is on the stack
12855       {
12856         75/jump-if-!= break/disp8
12857 $emit-cleanup-code-until-depth:var-on-stack:
12858         (size-of %ebx)  # => eax
12859         # don't emit code for labels
12860         3d/compare-eax-and 0/imm32
12861         74/jump-if-= break/disp8
12862 $emit-cleanup-code-until-depth:reclaim-var-on-stack:
12863         (emit-indent *(ebp+8) *Curr-block-depth)
12864         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
12865         (write-int32-hex-buffered *(ebp+8) %eax)
12866         (write-buffered *(ebp+8) "/imm32\n")
12867       }
12868 $emit-cleanup-code-until-depth:continue:
12869       # curr -= 12
12870       81 5/subop/subtract %esi 0xc/imm32
12871       e9/jump loop/disp32
12872     }
12873 $emit-cleanup-code-until-depth:end:
12874     # . restore registers
12875     5e/pop-to-esi
12876     5b/pop-to-ebx
12877     5a/pop-to-edx
12878     59/pop-to-ecx
12879     58/pop-to-eax
12880     # . epilogue
12881     89/<- %esp 5/r32/ebp
12882     5d/pop-to-ebp
12883     c3/return
12884 
12885 # emit clean-up code for 'vars' until a given label is encountered
12886 # doesn't actually modify 'vars' so we need traverse manually inside the stack
12887 emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
12888     # . prologue
12889     55/push-ebp
12890     89/<- %ebp 4/r32/esp
12891     # . save registers
12892     50/push-eax
12893     51/push-ecx
12894     52/push-edx
12895     53/push-ebx
12896     # ecx = vars
12897     8b/-> *(ebp+0xc) 1/r32/ecx
12898     # var eax: int = vars->top
12899     8b/-> *ecx 0/r32/eax
12900     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
12901     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
12902     # var min/ecx: (addr handle var) = vars->data
12903     81 0/subop/add %ecx 8/imm32
12904     {
12905 $emit-cleanup-code-until-target:loop:
12906       # if (curr < min) break
12907       39/compare %edx 1/r32/ecx
12908       0f 82/jump-if-addr< break/disp32
12909       # var v/ebx: (handle var) = lookup(*curr)
12910       (lookup *edx *(edx+4))  # => eax
12911       89/<- %ebx 0/r32/eax
12912       # if (v->name == until-block-label) break
12913       (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
12914       (string-equal? %eax *(ebp+0x10))  # => eax
12915       3d/compare-eax-and 0/imm32/false
12916       0f 85/jump-if-!= break/disp32
12917       # if v is in a register
12918       81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
12919       {
12920         0f 84/jump-if-= break/disp32
12921         {
12922 $emit-cleanup-code-until-target:check-for-previous-spill:
12923           8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
12924           3d/compare-eax-and 0/imm32/false
12925           74/jump-if-= break/disp8
12926 $emit-cleanup-code-until-target:reclaim-var-in-register:
12927           (emit-indent *(ebp+8) *Curr-block-depth)
12928           (write-buffered *(ebp+8) "8f 0/subop/pop %")
12929           (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
12930           (write-buffered *(ebp+8) %eax)
12931           (write-buffered *(ebp+8) Newline)
12932         }
12933         eb/jump $emit-cleanup-code-until-target:continue/disp8
12934       }
12935       # otherwise v is on the stack
12936       {
12937         75/jump-if-!= break/disp8
12938 $emit-cleanup-code-until-target:reclaim-var-on-stack:
12939         (size-of %ebx)  # => eax
12940         # don't emit code for labels
12941         3d/compare-eax-and 0/imm32
12942         74/jump-if-= break/disp8
12943         #
12944         (emit-indent *(ebp+8) *Curr-block-depth)
12945         (write-buffered *(ebp+8) "81 0/subop/add %esp ")
12946         (write-int32-hex-buffered *(ebp+8) %eax)
12947         (write-buffered *(ebp+8) "/imm32\n")
12948       }
12949 $emit-cleanup-code-until-target:continue:
12950       # curr -= 12
12951       81 5/subop/subtract %edx 0xc/imm32
12952       e9/jump loop/disp32
12953     }
12954 $emit-cleanup-code-until-target:end:
12955     # . restore registers
12956     5b/pop-to-ebx
12957     5a/pop-to-edx
12958     59/pop-to-ecx
12959     58/pop-to-eax
12960     # . epilogue
12961     89/<- %esp 5/r32/ebp
12962     5d/pop-to-ebp
12963     c3/return
12964 
12965 # Return true if there isn't a variable in 'vars' with the same block-depth
12966 # and register as 'v'.
12967 # 'v' is guaranteed not to be within 'vars'.
12968 not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
12969     # . prologue
12970     55/push-ebp
12971     89/<- %ebp 4/r32/esp
12972     # . save registers
12973     51/push-ecx
12974     52/push-edx
12975     53/push-ebx
12976     56/push-esi
12977     57/push-edi
12978     # ecx = vars
12979     8b/-> *(ebp+0xc) 1/r32/ecx
12980     # var eax: int = vars->top
12981     8b/-> *ecx 0/r32/eax
12982     # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
12983     8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
12984     # var min/ecx: (addr handle var) = vars->data
12985     8d/copy-address *(ecx+8) 1/r32/ecx
12986     # var depth/ebx: int = v->block-depth
12987     8b/-> *(ebp+8) 3/r32/ebx
12988     8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
12989     # var needle/esi: (addr array byte) = v->register
12990     8b/-> *(ebp+8) 6/r32/esi
12991     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
12992     89/<- %esi 0/r32/eax
12993     {
12994 $not-yet-spilled-this-block?:loop:
12995       # if (curr < min) break
12996       39/compare %edx 1/r32/ecx
12997       0f 82/jump-if-addr< break/disp32
12998       # var cand/edi: (addr var) = lookup(*curr)
12999       (lookup *edx *(edx+4))  # => eax
13000       89/<- %edi 0/r32/eax
13001       # if (cand->block-depth < depth) break
13002       39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
13003       0f 8c/jump-if-< break/disp32
13004       # var cand-reg/edi: (array array byte) = cand->reg
13005       (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
13006       89/<- %edi 0/r32/eax
13007       # if (cand-reg == null) continue
13008       {
13009 $not-yet-spilled-this-block?:check-reg:
13010         81 7/subop/compare %edi 0/imm32
13011         0f 84/jump-if-= break/disp32
13012         # if (cand-reg == needle) return true
13013         (string-equal? %esi %edi)  # => eax
13014         3d/compare-eax-and 0/imm32/false
13015         74/jump-if-= break/disp8
13016 $not-yet-spilled-this-block?:return-false:
13017         b8/copy-to-eax 0/imm32/false
13018         eb/jump $not-yet-spilled-this-block?:end/disp8
13019       }
13020 $not-yet-spilled-this-block?:continue:
13021       # curr -= 12
13022       81 5/subop/subtract %edx 0xc/imm32
13023       e9/jump loop/disp32
13024     }
13025 $not-yet-spilled-this-block?:return-true:
13026     # return true
13027     b8/copy-to-eax 1/imm32/true
13028 $not-yet-spilled-this-block?:end:
13029     # . restore registers
13030     5f/pop-to-edi
13031     5e/pop-to-esi
13032     5b/pop-to-ebx
13033     5a/pop-to-edx
13034     59/pop-to-ecx
13035     # . epilogue
13036     89/<- %esp 5/r32/ebp
13037     5d/pop-to-ebp
13038     c3/return
13039 
13040 # could the register of 'v' ever be written to by one of the vars in fn-outputs?
13041 will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
13042     # . prologue
13043     55/push-ebp
13044     89/<- %ebp 4/r32/esp
13045     # eax = v
13046     8b/-> *(ebp+8) 0/r32/eax
13047     # var reg/eax: (addr array byte) = lookup(v->register)
13048     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13049     # var target/eax: (addr var) = find-register(fn-outputs, reg)
13050     (find-register *(ebp+0x10) %eax)  # => eax
13051     # if (target == 0) return true
13052     {
13053       3d/compare-eax-and 0/imm32
13054       75/jump-if-!= break/disp8
13055       b8/copy-to-eax 1/imm32/true
13056       eb/jump $will-not-write-some-register?:end/disp8
13057     }
13058     # return !assigns-in-stmts?(stmts, target)
13059     (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
13060     3d/compare-eax-and 0/imm32/false
13061     # assume: true = 1, so no need to mask with 0x000000ff
13062     0f 94/set-if-= %al
13063 $will-not-write-some-register?:end:
13064     # . epilogue
13065     89/<- %esp 5/r32/ebp
13066     5d/pop-to-ebp
13067     c3/return
13068 
13069 # return fn output with matching register
13070 # always returns false if 'reg' is null
13071 find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
13072     # . prologue
13073     55/push-ebp
13074     89/<- %ebp 4/r32/esp
13075     # . save registers
13076     51/push-ecx
13077     # var curr/ecx: (addr list var) = lookup(fn->outputs)
13078     8b/-> *(ebp+8) 1/r32/ecx
13079     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
13080     89/<- %ecx 0/r32/eax
13081     {
13082 $find-register:loop:
13083       # if (curr == 0) break
13084       81 7/subop/compare %ecx 0/imm32
13085       74/jump-if-= break/disp8
13086       # eax = curr->value->register
13087       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13088       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13089       # if (eax == reg) return curr->value
13090 $find-register:compare:
13091       (string-equal? *(ebp+0xc) %eax)  # => eax
13092       {
13093         3d/compare-eax-and 0/imm32/false
13094         74/jump-if-= break/disp8
13095 $find-register:found:
13096         (lookup *ecx *(ecx+4))  # List-value List-value => eax
13097         eb/jump $find-register:end/disp8
13098       }
13099       # curr = lookup(curr->next)
13100       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13101       89/<- %ecx 0/r32/eax
13102       #
13103       eb/jump loop/disp8
13104     }
13105 $find-register:end:
13106     # . restore registers
13107     59/pop-to-ecx
13108     # . epilogue
13109     89/<- %esp 5/r32/ebp
13110     5d/pop-to-ebp
13111     c3/return
13112 
13113 assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
13114     # . prologue
13115     55/push-ebp
13116     89/<- %ebp 4/r32/esp
13117     # . save registers
13118     51/push-ecx
13119     # var curr/ecx: (addr list stmt) = stmts
13120     8b/-> *(ebp+8) 1/r32/ecx
13121     {
13122       # if (curr == 0) break
13123       81 7/subop/compare %ecx 0/imm32
13124       74/jump-if-= break/disp8
13125       # if assigns-in-stmt?(curr->value, v) return true
13126       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13127       (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
13128       3d/compare-eax-and 0/imm32/false
13129       75/jump-if-!= break/disp8
13130       # curr = lookup(curr->next)
13131       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13132       89/<- %ecx 0/r32/eax
13133       #
13134       eb/jump loop/disp8
13135     }
13136 $assigns-in-stmts?:end:
13137     # . restore registers
13138     59/pop-to-ecx
13139     # . epilogue
13140     89/<- %esp 5/r32/ebp
13141     5d/pop-to-ebp
13142     c3/return
13143 
13144 assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
13145     # . prologue
13146     55/push-ebp
13147     89/<- %ebp 4/r32/esp
13148     # . save registers
13149     51/push-ecx
13150     # ecx = stmt
13151     8b/-> *(ebp+8) 1/r32/ecx
13152     # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
13153     {
13154       81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
13155       75/jump-if-!= break/disp8
13156       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13157       (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
13158       eb/jump $assigns-in-stmt?:end/disp8
13159     }
13160     # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
13161     {
13162       81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
13163       75/jump-if-!= break/disp8
13164       (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
13165       (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
13166       eb/jump $assigns-in-stmt?:end/disp8
13167     }
13168     # otherwise return false
13169     b8/copy 0/imm32/false
13170 $assigns-in-stmt?:end:
13171     # . restore registers
13172     59/pop-to-ecx
13173     # . epilogue
13174     89/<- %esp 5/r32/ebp
13175     5d/pop-to-ebp
13176     c3/return
13177 
13178 assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
13179     # . prologue
13180     55/push-ebp
13181     89/<- %ebp 4/r32/esp
13182     # . save registers
13183     51/push-ecx
13184     # var curr/ecx: (addr stmt-var) = stmt-var
13185     8b/-> *(ebp+8) 1/r32/ecx
13186     {
13187       # if (curr == 0) break
13188       81 7/subop/compare %ecx 0/imm32
13189       74/jump-if-= break/disp8
13190       # eax = lookup(curr->value)
13191       (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
13192       # if (eax == v  &&  curr->is-deref? == false) return true
13193       {
13194         39/compare *(ebp+0xc) 0/r32/eax
13195         75/jump-if-!= break/disp8
13196         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
13197         75/jump-if-!= break/disp8
13198         b8/copy-to-eax 1/imm32/true
13199         eb/jump $assigns-in-stmt-vars?:end/disp8
13200       }
13201       # curr = lookup(curr->next)
13202       (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
13203       89/<- %ecx 0/r32/eax
13204       #
13205       eb/jump loop/disp8
13206     }
13207 $assigns-in-stmt-vars?:end:
13208     # . restore registers
13209     59/pop-to-ecx
13210     # . epilogue
13211     89/<- %esp 5/r32/ebp
13212     5d/pop-to-ebp
13213     c3/return
13214 
13215 # is there a var before 'v' with the same block-depth and register on the 'vars' stack?
13216 # v is guaranteed to be within vars
13217 # 'start' is provided as an optimization, a pointer within vars
13218 # *start == v
13219 same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
13220     # . prologue
13221     55/push-ebp
13222     89/<- %ebp 4/r32/esp
13223     # . save registers
13224     51/push-ecx
13225     52/push-edx
13226     53/push-ebx
13227     56/push-esi
13228     57/push-edi
13229     # ecx = v
13230     8b/-> *(ebp+8) 1/r32/ecx
13231     # var reg/edx: (addr array byte) = lookup(v->register)
13232     (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
13233     89/<- %edx 0/r32/eax
13234     # var depth/ebx: int = v->block-depth
13235     8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
13236     # var min/ecx: (addr handle var) = vars->data
13237     8b/-> *(ebp+0xc) 1/r32/ecx
13238     81 0/subop/add %ecx 8/imm32
13239     # TODO: check that start >= min and start < &vars->data[top]
13240     # TODO: check that *start == v
13241     # var curr/esi: (addr handle var) = start
13242     8b/-> *(ebp+0x10) 6/r32/esi
13243     # curr -= 8
13244     81 5/subop/subtract %esi 8/imm32
13245     {
13246 $same-register-spilled-before?:loop:
13247       # if (curr < min) break
13248       39/compare %esi 1/r32/ecx
13249       0f 82/jump-if-addr< break/disp32
13250       # var x/eax: (addr var) = lookup(*curr)
13251       (lookup *esi *(esi+4))  # => eax
13252       # if (x->block-depth < depth) break
13253       39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
13254       0f 8c/jump-if-< break/disp32
13255       # if (x->register == 0) continue
13256       81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
13257       74/jump-if-= $same-register-spilled-before?:continue/disp8
13258       # if (x->register == reg) return true
13259       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13260       (string-equal? %eax %edx)  # => eax
13261       3d/compare-eax-and 0/imm32/false
13262       b8/copy-to-eax 1/imm32/true
13263       75/jump-if-!= $same-register-spilled-before?:end/disp8
13264 $same-register-spilled-before?:continue:
13265       # curr -= 8
13266       81 5/subop/subtract %esi 8/imm32
13267       e9/jump loop/disp32
13268     }
13269 $same-register-spilled-before?:false:
13270     b8/copy-to-eax 0/imm32/false
13271 $same-register-spilled-before?:end:
13272     # . restore registers
13273     5f/pop-to-edi
13274     5e/pop-to-esi
13275     5b/pop-to-ebx
13276     5a/pop-to-edx
13277     59/pop-to-ecx
13278     # . epilogue
13279     89/<- %esp 5/r32/ebp
13280     5d/pop-to-ebp
13281     c3/return
13282 
13283 # Clean up global state for 'vars' until some block depth (inclusive).
13284 #
13285 # This would be a simple series of pops, if it wasn't for fn outputs, which
13286 # can occur anywhere in the stack.
13287 # So we have to _compact_ the entire array underlying the stack.
13288 #
13289 # We want to allow a fn output register to be written to by locals before the
13290 # output is set.
13291 # So fn outputs can't just be pushed at the start of the function.
13292 #
13293 # We want to allow other locals to shadow a fn output register after the
13294 # output is set.
13295 # So the output can't just always override anything in the stack. Sequence matters.
13296 clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
13297     # pseudocode:
13298     #   to = vars->top  (which points outside the stack)
13299     #   while true
13300     #     if to <= 0
13301     #       break
13302     #     var v = vars->data[to-1]
13303     #     if v.depth < until and !in-function-outputs?(fn, v)
13304     #       break
13305     #     --to
13306     #   from = to
13307     #   while true
13308     #     if from >= vars->top
13309     #       break
13310     #     assert(from >= to)
13311     #     v = vars->data[from]
13312     #     if in-function-outputs?(fn, v)
13313     #       if from > to
13314     #         vars->data[to] = vars->data[from]
13315     #       ++to
13316     #     ++from
13317     #   vars->top = to
13318     #
13319     # . prologue
13320     55/push-ebp
13321     89/<- %ebp 4/r32/esp
13322     # . save registers
13323     50/push-eax
13324     52/push-edx
13325     53/push-ebx
13326     56/push-esi
13327     57/push-edi
13328     # ebx = vars
13329     8b/-> *(ebp+8) 3/r32/ebx
13330     # edx = until-block-depth
13331     8b/-> *(ebp+0xc) 2/r32/edx
13332 $clean-up-blocks:phase1:
13333     # var to/edi: int = vars->top
13334     8b/-> *ebx 7/r32/edi
13335     {
13336 $clean-up-blocks:loop1:
13337       # if (to <= 0) break
13338       81 7/subop/compare %edi 0/imm32
13339       7e/jump-if-<= break/disp8
13340       # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
13341       8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
13342       (lookup *eax *(eax+4))  # => eax
13343       # if (v->block-depth >= until-block-depth) continue
13344       39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
13345       {
13346         7d/jump-if->= break/disp8
13347         # if (!in-function-outputs?(fn, v)) break
13348         (in-function-outputs? *(ebp+0x10) %eax)  # => eax
13349         3d/compare-eax-and 0/imm32/false
13350         74/jump-if-= $clean-up-blocks:phase2/disp8
13351       }
13352 $clean-up-blocks:loop1-continue:
13353       # --to
13354       81 5/subop/subtract %edi 0xc/imm32
13355       #
13356       eb/jump loop/disp8
13357     }
13358 $clean-up-blocks:phase2:
13359     # var from/esi: int = to
13360     89/<- %esi 7/r32/edi
13361     {
13362 $clean-up-blocks:loop2:
13363       # if (from >= vars->top) break
13364       3b/compare 6/r32/esi *ebx
13365       7d/jump-if->= break/disp8
13366       # var v/eax: (addr var) = lookup(vars->data[from]->var)
13367       8d/copy-address *(ebx+esi+8) 0/r32/eax
13368       (lookup *eax *(eax+4))  # => eax
13369       # if !in-function-outputs?(fn, v) continue
13370       (in-function-outputs? *(ebp+0x10) %eax)  # => eax
13371       3d/compare-eax-and 0/imm32/false
13372       74/jump-if-= $clean-up-blocks:loop2-continue/disp8
13373       # invariant: from >= to
13374       # if (from > to) vars->data[to] = vars->data[from]
13375       {
13376         39/compare %esi 7/r32/edi
13377         7e/jump-if-<= break/disp8
13378         56/push-esi
13379         57/push-edi
13380         # . var from/esi: (addr byte) = &vars->data[from]
13381         8d/copy-address *(ebx+esi+8) 6/r32/esi
13382         # . var to/edi: (addr byte) = &vars->data[to]
13383         8d/copy-address *(ebx+edi+8) 7/r32/edi
13384         # .
13385         8b/-> *esi 0/r32/eax
13386         89/<- *edi 0/r32/eax
13387         8b/-> *(esi+4) 0/r32/eax
13388         89/<- *(edi+4) 0/r32/eax
13389         8b/-> *(esi+8) 0/r32/eax
13390         89/<- *(edi+8) 0/r32/eax
13391         5f/pop-to-edi
13392         5e/pop-to-esi
13393       }
13394       # ++to
13395       81 0/subop/add %edi 0xc/imm32
13396 $clean-up-blocks:loop2-continue:
13397       # ++from
13398       81 0/subop/add %esi 0xc/imm32
13399       #
13400       eb/jump loop/disp8
13401     }
13402     89/<- *ebx 7/r32/edi
13403 $clean-up-blocks:end:
13404     # . restore registers
13405     5f/pop-to-edi
13406     5e/pop-to-esi
13407     5b/pop-to-ebx
13408     5a/pop-to-edx
13409     58/pop-to-eax
13410     # . epilogue
13411     89/<- %esp 5/r32/ebp
13412     5d/pop-to-ebp
13413     c3/return
13414 
13415 in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
13416     # . prologue
13417     55/push-ebp
13418     89/<- %ebp 4/r32/esp
13419     # . save registers
13420     51/push-ecx
13421     # var curr/ecx: (addr list var) = lookup(fn->outputs)
13422     8b/-> *(ebp+8) 1/r32/ecx
13423     (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
13424     89/<- %ecx 0/r32/eax
13425     # while curr != null
13426     {
13427       81 7/subop/compare %ecx 0/imm32
13428       74/jump-if-= break/disp8
13429       # var v/eax: (addr var) = lookup(curr->value)
13430       (lookup *ecx *(ecx+4))  # List-value List-value => eax
13431       # if (v == target) return true
13432       39/compare *(ebp+0xc) 0/r32/eax
13433       b8/copy-to-eax 1/imm32/true
13434       74/jump-if-= $in-function-outputs?:end/disp8
13435       # curr = curr->next
13436       (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
13437       89/<- %ecx 0/r32/eax
13438       #
13439       eb/jump loop/disp8
13440     }
13441     b8/copy-to-eax 0/imm32
13442 $in-function-outputs?:end:
13443     # . restore registers
13444     59/pop-to-ecx
13445     # . epilogue
13446     89/<- %esp 5/r32/ebp
13447     5d/pop-to-ebp
13448     c3/return
13449 
13450 emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
13451     # . prologue
13452     55/push-ebp
13453     89/<- %ebp 4/r32/esp
13454     # . save registers
13455     50/push-eax
13456     51/push-ecx
13457     52/push-edx
13458     # eax = stmt
13459     8b/-> *(ebp+0xc) 0/r32/eax
13460     # var v/ecx: (addr var)
13461     (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
13462     89/<- %ecx 0/r32/eax
13463     # v->block-depth = *Curr-block-depth
13464     8b/-> *Curr-block-depth 0/r32/eax
13465     89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
13466     # var n/edx: int = size-of(stmt->var)
13467     (size-of %ecx)  # => eax
13468     89/<- %edx 0/r32/eax
13469     # *Curr-local-stack-offset -= n
13470     29/subtract-from *Curr-local-stack-offset 2/r32/edx
13471     # v->offset = *Curr-local-stack-offset
13472     8b/-> *Curr-local-stack-offset 0/r32/eax
13473     89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
13474     # if v is an array, do something special
13475     {
13476       (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
13477       (is-mu-array? %eax)  # => eax
13478       3d/compare-eax-and 0/imm32/false
13479       0f 84/jump-if-= break/disp32
13480       # var array-size-without-size/edx: int = n-4
13481       81 5/subop/subtract %edx 4/imm32
13482       (emit-indent *(ebp+8) *Curr-block-depth)
13483       (write-buffered *(ebp+8) "(push-n-zero-bytes ")
13484       (write-int32-hex-buffered *(ebp+8) %edx)
13485       (write-buffered *(ebp+8) ")\n")
13486       (emit-indent *(ebp+8) *Curr-block-depth)
13487       (write-buffered *(ebp+8) "68/push ")
13488       (write-int32-hex-buffered *(ebp+8) %edx)
13489       (write-buffered *(ebp+8) "/imm32\n")
13490       eb/jump $emit-subx-var-def:end/disp8
13491     }
13492     # while n > 0
13493     {
13494       81 7/subop/compare %edx 0/imm32
13495       7e/jump-if-<= break/disp8
13496       (emit-indent *(ebp+8) *Curr-block-depth)
13497       (write-buffered *(ebp+8) "68/push 0/imm32\n")
13498       # n -= 4
13499       81 5/subop/subtract %edx 4/imm32
13500       #
13501       eb/jump loop/disp8
13502     }
13503 $emit-subx-var-def:end:
13504     # . restore registers
13505     5a/pop-to-edx
13506     59/pop-to-ecx
13507     58/pop-to-eax
13508     # . epilogue
13509     89/<- %esp 5/r32/ebp
13510     5d/pop-to-ebp
13511     c3/return
13512 
13513 emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
13514     # . prologue
13515     55/push-ebp
13516     89/<- %ebp 4/r32/esp
13517     # . save registers
13518     50/push-eax
13519     51/push-ecx
13520     # - some special-case primitives that don't actually use the 'primitives' data structure
13521     # var op/ecx: (addr array byte) = lookup(stmt->operation)
13522     8b/-> *(ebp+0xc) 1/r32/ecx
13523     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
13524     89/<- %ecx 0/r32/eax
13525     # array size
13526     {
13527       # if (!string-equal?(stmt->operation, "length")) break
13528       (string-equal? %ecx "length")  # => eax
13529       3d/compare-eax-and 0/imm32
13530       0f 84/jump-if-= break/disp32
13531       (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13532       e9/jump $emit-subx-stmt:end/disp32
13533     }
13534     # index into array
13535     {
13536       # if (!string-equal?(stmt->operation, "index")) break
13537       (string-equal? %ecx "index")  # => eax
13538       3d/compare-eax-and 0/imm32
13539       0f 84/jump-if-= break/disp32
13540       (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13541       e9/jump $emit-subx-stmt:end/disp32
13542     }
13543     # compute-offset for index into array
13544     {
13545       # if (!string-equal?(stmt->operation, "compute-offset")) break
13546       (string-equal? %ecx "compute-offset")  # => eax
13547       3d/compare-eax-and 0/imm32
13548       0f 84/jump-if-= break/disp32
13549       (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
13550       e9/jump $emit-subx-stmt:end/disp32
13551     }
13552     # get field from record
13553     {
13554       # if (!string-equal?(stmt->operation, "get")) break
13555       (string-equal? %ecx "get")  # => eax
13556       3d/compare-eax-and 0/imm32
13557       0f 84/jump-if-= break/disp32
13558       (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
13559       e9/jump $emit-subx-stmt:end/disp32
13560     }
13561     # - if stmt matches a primitive, emit it
13562     {
13563 $emit-subx-stmt:check-for-primitive:
13564       # var curr/eax: (addr primitive)
13565       (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
13566       3d/compare-eax-and 0/imm32
13567       74/jump-if-= break/disp8
13568 $emit-subx-stmt:primitive:
13569       (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
13570       e9/jump $emit-subx-stmt:end/disp32
13571     }
13572     # - otherwise emit a call
13573     # TODO: type-checking
13574 $emit-subx-stmt:call:
13575     (emit-call *(ebp+8) *(ebp+0xc))
13576 $emit-subx-stmt:end:
13577     # . restore registers
13578     59/pop-to-ecx
13579     58/pop-to-eax
13580     # . epilogue
13581     89/<- %esp 5/r32/ebp
13582     5d/pop-to-ebp
13583     c3/return
13584 
13585 translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13586     # . prologue
13587     55/push-ebp
13588     89/<- %ebp 4/r32/esp
13589     # . save registers
13590     50/push-eax
13591     51/push-ecx
13592     52/push-edx
13593     53/push-ebx
13594     56/push-esi
13595     # esi = stmt
13596     8b/-> *(ebp+0xc) 6/r32/esi
13597     # var base/ebx: (addr var) = stmt->inouts[0]->value
13598     (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13599     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13600     89/<- %ebx 0/r32/eax
13601     # var elemsize/ecx: int = array-element-size(base)
13602     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13603     89/<- %ecx 0/r32/eax
13604     # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
13605     (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13606     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13607     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13608     89/<- %edx 0/r32/eax
13609     # if elemsize == 1
13610     {
13611       81 7/subop/compare %ecx 1/imm32
13612       75/jump-if-!= break/disp8
13613 $translate-mu-length-stmt:size-1:
13614       (emit-save-size-to *(ebp+8) %ebx %edx)
13615       e9/jump $translate-mu-length-stmt:end/disp32
13616     }
13617     # if elemsize is a power of 2 less than 256
13618     {
13619       (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
13620       3d/compare-eax-and 0/imm32/false
13621       74/jump-if-= break/disp8
13622       81 7/subop/compare %ecx 0xff/imm32
13623       7f/jump-if-> break/disp8
13624 $translate-mu-length-stmt:size-power-of-2:
13625       (emit-save-size-to *(ebp+8) %ebx %edx)
13626       (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
13627       e9/jump $translate-mu-length-stmt:end/disp32
13628     }
13629     # otherwise, the complex case
13630     # . emit register spills
13631     {
13632 $translate-mu-length-stmt:complex:
13633       (string-equal? %edx "eax")  # => eax
13634       3d/compare-eax-and 0/imm32/false
13635       75/break-if-!= break/disp8
13636       (emit-indent *(ebp+8) *Curr-block-depth)
13637       (write-buffered *(ebp+8) "50/push-eax\n")
13638     }
13639     {
13640       (string-equal? %edx "ecx")  # => eax
13641       3d/compare-eax-and 0/imm32/false
13642       75/break-if-!= break/disp8
13643       (emit-indent *(ebp+8) *Curr-block-depth)
13644       (write-buffered *(ebp+8) "51/push-ecx\n")
13645     }
13646     {
13647       (string-equal? %edx "edx")  # => eax
13648       3d/compare-eax-and 0/imm32/false
13649       75/break-if-!= break/disp8
13650       (emit-indent *(ebp+8) *Curr-block-depth)
13651       (write-buffered *(ebp+8) "52/push-edx\n")
13652     }
13653     # .
13654     (emit-save-size-to *(ebp+8) %ebx "eax")
13655     (emit-indent *(ebp+8) *Curr-block-depth)
13656     (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
13657     (emit-indent *(ebp+8) *Curr-block-depth)
13658     (write-buffered *(ebp+8) "b9/copy-to-ecx ")
13659     (write-int32-hex-buffered *(ebp+8) %ecx)
13660     (write-buffered *(ebp+8) "/imm32\n")
13661     (emit-indent *(ebp+8) *Curr-block-depth)
13662     (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
13663     {
13664       (string-equal? %edx "eax")  # => eax
13665       3d/compare-eax-and 0/imm32/false
13666       75/break-if-!= break/disp8
13667       (emit-indent *(ebp+8) *Curr-block-depth)
13668       (write-buffered *(ebp+8) "89/<- %")
13669       (write-buffered *(ebp+8) %edx)
13670       (write-buffered *(ebp+8) " 0/r32/eax\n")
13671     }
13672     # . emit register restores
13673     {
13674       (string-equal? %edx "edx")  # => eax
13675       3d/compare-eax-and 0/imm32/false
13676       75/break-if-!= break/disp8
13677       (emit-indent *(ebp+8) *Curr-block-depth)
13678       (write-buffered *(ebp+8) "5a/pop-to-edx\n")
13679     }
13680     {
13681       (string-equal? %edx "ecx")  # => eax
13682       3d/compare-eax-and 0/imm32/false
13683       75/break-if-!= break/disp8
13684       (emit-indent *(ebp+8) *Curr-block-depth)
13685       (write-buffered *(ebp+8) "59/pop-to-ecx\n")
13686     }
13687     {
13688       (string-equal? %edx "eax")  # => eax
13689       3d/compare-eax-and 0/imm32/false
13690       75/break-if-!= break/disp8
13691       (emit-indent *(ebp+8) *Curr-block-depth)
13692       (write-buffered *(ebp+8) "58/pop-to-eax\n")
13693     }
13694 $translate-mu-length-stmt:end:
13695     # . restore registers
13696     5e/pop-to-esi
13697     5b/pop-to-ebx
13698     5a/pop-to-edx
13699     59/pop-to-ecx
13700     58/pop-to-eax
13701     # . epilogue
13702     89/<- %esp 5/r32/ebp
13703     5d/pop-to-ebp
13704     c3/return
13705 
13706 array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
13707     # . prologue
13708     55/push-ebp
13709     89/<- %ebp 4/r32/esp
13710     #
13711     (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
13712     (size-of-type-id-as-array-element %eax)  # => eax
13713 $array-element-size:end:
13714     # . epilogue
13715     89/<- %esp 5/r32/ebp
13716     5d/pop-to-ebp
13717     c3/return
13718 
13719 size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
13720     # . prologue
13721     55/push-ebp
13722     89/<- %ebp 4/r32/esp
13723     # eax = t
13724     8b/-> *(ebp+8) 0/r32/eax
13725     # if t is 'byte', size is 1
13726     3d/compare-eax-and 8/imm32/byte
13727     {
13728       75/jump-if-!= break/disp8
13729       b8/copy-to-eax 1/imm32
13730       eb/jump $array-element-size:end/disp8
13731     }
13732     # otherwise proceed as usual
13733     (size-of-type-id %eax)  # => eax
13734 $size-of-type-id-as-array-element:end:
13735     # . epilogue
13736     89/<- %esp 5/r32/ebp
13737     5d/pop-to-ebp
13738     c3/return
13739 
13740 emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
13741     # . prologue
13742     55/push-ebp
13743     89/<- %ebp 4/r32/esp
13744     # . save registers
13745     50/push-eax
13746     53/push-ebx
13747     # ebx = base
13748     8b/-> *(ebp+0xc) 3/r32/ebx
13749     (emit-indent *(ebp+8) *Curr-block-depth)
13750     (write-buffered *(ebp+8) "8b/-> *")
13751     # if base is an (addr array ...) in a register
13752     {
13753       81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
13754       74/jump-if-= break/disp8
13755 $emit-save-size-to:emit-base-from-register:
13756       (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13757       (write-buffered *(ebp+8) %eax)
13758       eb/jump $emit-save-size-to:emit-output/disp8
13759     }
13760     # otherwise if base is an (array ...) on the stack
13761     {
13762       81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
13763       74/jump-if-= break/disp8
13764 $emit-save-size-to:emit-base-from-stack:
13765       (write-buffered *(ebp+8) "(ebp+")
13766       (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
13767       (write-buffered *(ebp+8) ")")
13768     }
13769 $emit-save-size-to:emit-output:
13770     (write-buffered *(ebp+8) " ")
13771     (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
13772     (write-int32-hex-buffered *(ebp+8) *eax)
13773     (write-buffered *(ebp+8) "/r32\n")
13774 $emit-save-size-to:end:
13775     # . restore registers
13776     5b/pop-to-ebx
13777     58/pop-to-eax
13778     # . epilogue
13779     89/<- %esp 5/r32/ebp
13780     5d/pop-to-ebp
13781     c3/return
13782 
13783 emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
13784     # . prologue
13785     55/push-ebp
13786     89/<- %ebp 4/r32/esp
13787     # . save registers
13788     50/push-eax
13789     #
13790     (emit-indent *(ebp+8) *Curr-block-depth)
13791     (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
13792     (write-buffered *(ebp+8) *(ebp+0xc))
13793     (write-buffered *(ebp+8) Space)
13794     (num-shift-rights *(ebp+0x10))  # => eax
13795     (write-int32-hex-buffered *(ebp+8) %eax)
13796     (write-buffered *(ebp+8) "/imm8\n")
13797 $emit-divide-by-shift-right:end:
13798     # . restore registers
13799     58/pop-to-eax
13800     # . epilogue
13801     89/<- %esp 5/r32/ebp
13802     5d/pop-to-ebp
13803     c3/return
13804 
13805 translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13806     # . prologue
13807     55/push-ebp
13808     89/<- %ebp 4/r32/esp
13809     # . save registers
13810     51/push-ecx
13811     # ecx = stmt
13812     8b/-> *(ebp+0xc) 1/r32/ecx
13813     # var base/ecx: (addr var) = stmt->inouts[0]
13814     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13815     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13816     89/<- %ecx 0/r32/eax
13817     # if (var->register) do one thing
13818     {
13819       81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
13820       74/jump-if-= break/disp8
13821       # TODO: ensure there's no dereference
13822       (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13823       eb/jump $translate-mu-index-stmt:end/disp8
13824     }
13825     # if (var->offset) do a different thing
13826     {
13827       81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
13828       74/jump-if-= break/disp8
13829       # TODO: ensure there's no dereference
13830       (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
13831       eb/jump $translate-mu-index-stmt:end/disp8
13832     }
13833 $translate-mu-index-stmt:end:
13834     # . restore registers
13835     59/pop-to-ecx
13836     # . epilogue
13837     89/<- %esp 5/r32/ebp
13838     5d/pop-to-ebp
13839     c3/return
13840 
13841 $translate-mu-index-stmt-with-array:error1:
13842     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
13843     (flush *(ebp+0x10))
13844     (stop *(ebp+0x14) 1)
13845     # never gets here
13846 
13847 $translate-mu-index-stmt-with-array:error2:
13848     (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
13849     (flush *(ebp+0x10))
13850     (stop *(ebp+0x14) 1)
13851     # never gets here
13852 
13853 translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13854     # . prologue
13855     55/push-ebp
13856     89/<- %ebp 4/r32/esp
13857     # . save registers
13858     50/push-eax
13859     51/push-ecx
13860     52/push-edx
13861     53/push-ebx
13862     #
13863     (emit-indent *(ebp+8) *Curr-block-depth)
13864     (write-buffered *(ebp+8) "8d/copy-address *(")
13865     # TODO: ensure inouts[0] is in a register and not dereferenced
13866 $translate-mu-index-stmt-with-array-in-register:emit-base:
13867     # ecx = stmt
13868     8b/-> *(ebp+0xc) 1/r32/ecx
13869     # var base/ebx: (addr var) = inouts[0]
13870     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13871     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13872     89/<- %ebx 0/r32/eax
13873     # print base->register " + "
13874     (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
13875     (write-buffered *(ebp+8) %eax)
13876     (write-buffered *(ebp+8) " + ")
13877     # var index/edx: (addr var) = inouts[1]
13878     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13879     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
13880     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13881     89/<- %edx 0/r32/eax
13882     # if index->register
13883     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
13884     {
13885       0f 84/jump-if-= break/disp32
13886 $translate-mu-index-stmt-with-array-in-register:emit-register-index:
13887       # if index is an int
13888       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13889       (is-simple-mu-type? %eax 1)  # int => eax
13890       3d/compare-eax-and 0/imm32/false
13891       {
13892         0f 84/jump-if-= break/disp32
13893 $translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
13894         # print index->register "<<" log2(array-element-size(base)) " + 4) "
13895         # . index->register "<<"
13896         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13897         (write-buffered *(ebp+8) %eax)
13898         (write-buffered *(ebp+8) "<<")
13899         # . log2(array-element-size(base->type))
13900         # TODO: ensure size is a power of 2
13901         (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13902         (num-shift-rights %eax)  # => eax
13903         (write-int32-hex-buffered *(ebp+8) %eax)
13904         e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
13905       }
13906       # if index->type is any other atom, abort
13907       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13908       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
13909       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
13910       # if index has type (offset ...)
13911       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
13912       (is-simple-mu-type? %eax 7)  # => eax
13913       3d/compare-eax-and 0/imm32/false
13914       {
13915         0f 84/jump-if-= break/disp32
13916         # print index->register
13917 $translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
13918         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
13919         (write-buffered *(ebp+8) %eax)
13920       }
13921 $translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
13922       (write-buffered *(ebp+8) " + 4) ")
13923       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
13924     }
13925     # otherwise if index is a literal
13926     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
13927     (is-simple-mu-type? %eax 0)  # => eax
13928     3d/compare-eax-and 0/imm32/false
13929     {
13930       0f 84/jump-if-= break/disp32
13931 $translate-mu-index-stmt-with-array-in-register:emit-literal-index:
13932       # var index-value/edx: int = parse-hex-int(index->name)
13933       (lookup *edx *(edx+4))  # Var-name Var-name => eax
13934       (parse-hex-int %eax)  # => eax
13935       89/<- %edx 0/r32/eax
13936       # offset = idx-value * array-element-size(base->type)
13937       (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
13938       f7 4/subop/multiply-into-eax %edx  # clobbers edx
13939       # offset += 4 for array size
13940       05/add-to-eax 4/imm32
13941       # TODO: check edx for overflow
13942       # print offset
13943       (write-int32-hex-buffered *(ebp+8) %eax)
13944       (write-buffered *(ebp+8) ") ")
13945       e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
13946     }
13947     # otherwise abort
13948     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
13949 $translate-mu-index-stmt-with-array-in-register:emit-output:
13950     # outputs[0] "/r32"
13951     8b/-> *(ebp+0xc) 1/r32/ecx
13952     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
13953     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13954     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
13955     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
13956     (write-int32-hex-buffered *(ebp+8) *eax)
13957     (write-buffered *(ebp+8) "/r32\n")
13958 $translate-mu-index-stmt-with-array-in-register:end:
13959     # . restore registers
13960     5b/pop-to-ebx
13961     5a/pop-to-edx
13962     59/pop-to-ecx
13963     58/pop-to-eax
13964     # . epilogue
13965     89/<- %esp 5/r32/ebp
13966     5d/pop-to-ebp
13967     c3/return
13968 
13969 translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
13970     # . prologue
13971     55/push-ebp
13972     89/<- %ebp 4/r32/esp
13973     # . save registers
13974     50/push-eax
13975     51/push-ecx
13976     52/push-edx
13977     53/push-ebx
13978     #
13979     (emit-indent *(ebp+8) *Curr-block-depth)
13980     (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
13981     # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
13982     8b/-> *(ebp+0xc) 0/r32/eax
13983     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
13984     89/<- %edx 0/r32/eax
13985     # var base/ecx: (addr var) = lookup(curr->value)
13986     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13987     89/<- %ecx 0/r32/eax
13988     # var curr2/eax: (addr stmt-var) = lookup(curr->next)
13989     (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
13990     # var index/edx: (handle var) = curr2->value
13991     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
13992     89/<- %edx 0/r32/eax
13993     # if index->register
13994     81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
13995     {
13996       0f 84/jump-if-= break/disp32
13997 $translate-mu-index-stmt-with-array-on-stack:emit-register-index:
13998       # if index is an int
13999       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14000       (is-simple-mu-type? %eax 1)  # int => eax
14001       3d/compare-eax-and 0/imm32/false
14002       {
14003         0f 84/jump-if-= break/disp32
14004 $translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
14005         # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
14006         # . inouts[1]->register "<<"
14007         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14008         (write-buffered *(ebp+8) %eax)
14009         (write-buffered *(ebp+8) "<<")
14010         # . log2(array-element-size(base))
14011         # TODO: ensure size is a power of 2
14012         (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14013         (num-shift-rights %eax)  # => eax
14014         (write-int32-hex-buffered *(ebp+8) %eax)
14015         #
14016         (write-buffered *(ebp+8) " + ")
14017         #
14018         8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
14019         05/add-to-eax 4/imm32  # for array length
14020         (write-int32-hex-buffered *(ebp+8) %eax)
14021         e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
14022       }
14023       # if index->type is any other atom, abort
14024       (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14025       81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14026       0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
14027       # if index has type (offset ...)
14028       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14029       (is-simple-mu-type? %eax 7)  # => eax
14030       3d/compare-eax-and 0/imm32/false
14031       {
14032         0f 84/jump-if-= break/disp32
14033         # print index->register
14034 $translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
14035         (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
14036         (write-buffered *(ebp+8) %eax)
14037       }
14038 $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
14039       (write-buffered *(ebp+8) ") ")
14040       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
14041     }
14042     # otherwise if index is a literal
14043     (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
14044     (is-simple-mu-type? %eax 0)  # => eax
14045     3d/compare-eax-and 0/imm32/false
14046     {
14047       0f 84/jump-if-= break/disp32
14048 $translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
14049       # var idx-value/edx: int = parse-hex-int(index->name)
14050       (lookup *edx *(edx+4))  # Var-name Var-name => eax
14051       (parse-hex-int %eax)  # Var-name => eax
14052       89/<- %edx 0/r32/eax
14053       # offset = idx-value * array-element-size(base)
14054       (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
14055       f7 4/subop/multiply-into-eax %edx  # clobbers edx
14056       # offset += base->offset
14057       03/add *(ecx+0x14) 0/r32/eax  # Var-offset
14058       # offset += 4 for array size
14059       05/add-to-eax 4/imm32
14060       # TODO: check edx for overflow
14061       # print offset
14062       (write-int32-hex-buffered *(ebp+8) %eax)
14063       (write-buffered *(ebp+8) ") ")
14064       e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
14065     }
14066     # otherwise abort
14067     e9/jump $translate-mu-index-stmt-with-array:error1/disp32
14068 $translate-mu-index-stmt-with-array-on-stack:emit-output:
14069     # outputs[0] "/r32"
14070     8b/-> *(ebp+0xc) 0/r32/eax
14071     (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14072     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14073     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14074     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
14075     (write-int32-hex-buffered *(ebp+8) *eax)
14076     (write-buffered *(ebp+8) "/r32\n")
14077 $translate-mu-index-stmt-with-array-on-stack:end:
14078     # . restore registers
14079     5b/pop-to-ebx
14080     5a/pop-to-edx
14081     59/pop-to-ecx
14082     58/pop-to-eax
14083     # . epilogue
14084     89/<- %esp 5/r32/ebp
14085     5d/pop-to-ebp
14086     c3/return
14087 
14088 translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
14089     # . prologue
14090     55/push-ebp
14091     89/<- %ebp 4/r32/esp
14092     # . save registers
14093     50/push-eax
14094     51/push-ecx
14095     52/push-edx
14096     53/push-ebx
14097     #
14098     (emit-indent *(ebp+8) *Curr-block-depth)
14099     (write-buffered *(ebp+8) "69/multiply")
14100     # ecx = stmt
14101     8b/-> *(ebp+0xc) 1/r32/ecx
14102     # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
14103     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14104     89/<- %ebx 0/r32/eax
14105 $translate-mu-compute-index-stmt:emit-index:
14106     (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
14107     (emit-subx-var-as-rm32 *(ebp+8) %eax)
14108     (write-buffered *(ebp+8) Space)
14109 $translate-mu-compute-index-stmt:emit-elem-size:
14110     # var base/ebx: (addr var)
14111     (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
14112     89/<- %ebx 0/r32/eax
14113     # print array-element-size(base)
14114     (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
14115     (write-int32-hex-buffered *(ebp+8) %eax)
14116     (write-buffered *(ebp+8) "/imm32 ")
14117 $translate-mu-compute-index-stmt:emit-output:
14118     # outputs[0] "/r32"
14119     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14120     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14121     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14122     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
14123     (write-int32-hex-buffered *(ebp+8) *eax)
14124     (write-buffered *(ebp+8) "/r32\n")
14125 $translate-mu-compute-index-stmt:end:
14126     # . restore registers
14127     5b/pop-to-ebx
14128     5a/pop-to-edx
14129     59/pop-to-ecx
14130     58/pop-to-eax
14131     # . epilogue
14132     89/<- %esp 5/r32/ebp
14133     5d/pop-to-ebp
14134     c3/return
14135 
14136 translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
14137     # . prologue
14138     55/push-ebp
14139     89/<- %ebp 4/r32/esp
14140     # . save registers
14141     50/push-eax
14142     51/push-ecx
14143     52/push-edx
14144     #
14145     (emit-indent *(ebp+8) *Curr-block-depth)
14146     (write-buffered *(ebp+8) "8d/copy-address ")
14147     # ecx = stmt
14148     8b/-> *(ebp+0xc) 1/r32/ecx
14149     # var offset/edx: int = get offset of stmt
14150     (mu-get-offset %ecx)  # => eax
14151     89/<- %edx 0/r32/eax
14152     # var base/eax: (addr var) = stmt->inouts->value
14153     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14154     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14155     # if base is in a register
14156     81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
14157     {
14158       0f 84/jump-if-= break/disp32
14159 $translate-mu-get-stmt:emit-register-input:
14160       # emit "*(" base->register " + " offset ") "
14161       (write-buffered *(ebp+8) "*(")
14162       (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14163       (write-buffered *(ebp+8) %eax)
14164       (write-buffered *(ebp+8) " + ")
14165       (write-int32-hex-buffered *(ebp+8) %edx)
14166       (write-buffered *(ebp+8) ") ")
14167       e9/jump $translate-mu-get-stmt:emit-output/disp32
14168     }
14169     # otherwise base is on the stack
14170     {
14171 $translate-mu-get-stmt:emit-stack-input:
14172       # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
14173       (write-buffered *(ebp+8) "*(ebp+")
14174       03/add *(eax+0x14) 2/r32/edx  # Var-offset
14175       (write-int32-hex-buffered *(ebp+8) %edx)
14176       (write-buffered *(ebp+8) ") ")
14177       eb/jump $translate-mu-get-stmt:emit-output/disp8
14178     }
14179 $translate-mu-get-stmt:emit-output:
14180     # var output/eax: (addr var) = stmt->outputs->value
14181     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
14182     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14183     # emit offset->register "/r32"
14184     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
14185     (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
14186     (write-int32-hex-buffered *(ebp+8) *eax)
14187     (write-buffered *(ebp+8) "/r32\n")
14188 $translate-mu-get-stmt:end:
14189     # . restore registers
14190     5a/pop-to-edx
14191     59/pop-to-ecx
14192     58/pop-to-eax
14193     # . epilogue
14194     89/<- %esp 5/r32/ebp
14195     5d/pop-to-ebp
14196     c3/return
14197 
14198 array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
14199     # precondition: n is positive
14200     # . prologue
14201     55/push-ebp
14202     89/<- %ebp 4/r32/esp
14203     #
14204     8b/-> *(ebp+8) 0/r32/eax
14205     # var t/eax: (addr type-tree)
14206     (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
14207     # if t == 0 abort
14208     3d/compare-eax-with 0/imm32
14209     0f 84/jump-if-== $array-element-type-id:error0/disp32
14210     # if t->is-atom? abort
14211     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14212     0f 85/jump-if-!= $array-element-type-id:error1/disp32
14213     # if (t->left == addr) t = t->right
14214     {
14215       50/push-eax
14216       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14217       (is-simple-mu-type? %eax 2)  # addr => eax
14218       3d/compare-eax-with 0/imm32/false
14219       58/pop-to-eax
14220       74/jump-if-= break/disp8
14221 $array-element-type-id:skip-addr:
14222       (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14223     }
14224     # if t == 0 abort
14225     3d/compare-eax-with 0/imm32
14226     0f 84/jump-if-= $array-element-type-id:error2/disp32
14227     # if t->is-atom? abort
14228     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14229     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14230     # if t->left != array abort
14231     {
14232       50/push-eax
14233       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14234       (is-simple-mu-type? %eax 3)  # array => eax
14235       3d/compare-eax-with 0/imm32/false
14236       58/pop-to-eax
14237 $array-element-type-id:no-array:
14238       0f 84/jump-if-= $array-element-type-id:error2/disp32
14239     }
14240 $array-element-type-id:skip-array:
14241     # t = t->right
14242     (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
14243     # if t == 0 abort
14244     3d/compare-eax-with 0/imm32
14245     0f 84/jump-if-= $array-element-type-id:error2/disp32
14246     # if t->is-atom? abort
14247     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
14248     0f 85/jump-if-!= $array-element-type-id:error2/disp32
14249     # return t->left->value
14250     (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
14251     8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
14252 $array-element-type-id:end:
14253     # . epilogue
14254     89/<- %esp 5/r32/ebp
14255     5d/pop-to-ebp
14256     c3/return
14257 
14258 $array-element-type-id:error0:
14259     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14260     50/push-eax
14261     8b/-> *(ebp+8) 0/r32/eax
14262     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14263     (write-buffered *(ebp+0xc) %eax)
14264     58/pop-to-eax
14265     (write-buffered *(ebp+0xc) "' has no type\n")
14266     (flush *(ebp+0xc))
14267     (stop *(ebp+0x10) 1)
14268     # never gets here
14269 
14270 $array-element-type-id:error1:
14271     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14272     50/push-eax
14273     8b/-> *(ebp+8) 0/r32/eax
14274     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14275     (write-buffered *(ebp+0xc) %eax)
14276     58/pop-to-eax
14277     (write-buffered *(ebp+0xc) "' has atomic type ")
14278     (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
14279     (write-buffered *(ebp+0xc) Newline)
14280     (flush *(ebp+0xc))
14281     (stop *(ebp+0x10) 1)
14282     # never gets here
14283 
14284 $array-element-type-id:error2:
14285     (write-buffered *(ebp+0xc) "array-element-type-id: var '")
14286     50/push-eax
14287     8b/-> *(ebp+8) 0/r32/eax
14288     (lookup *eax *(eax+4))  # Var-name Var-name => eax
14289     (write-buffered *(ebp+0xc) %eax)
14290     58/pop-to-eax
14291     (write-buffered *(ebp+0xc) "' has non-array type\n")
14292     (flush *(ebp+0xc))
14293     (stop *(ebp+0x10) 1)
14294     # never gets here
14295 
14296 power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
14297     # precondition: n is positive
14298     # . prologue
14299     55/push-ebp
14300     89/<- %ebp 4/r32/esp
14301     # eax = n
14302     8b/-> *(ebp+8) 0/r32/eax
14303     # if (n < 0) abort
14304     3d/compare-eax-with 0/imm32
14305     0f 8c/jump-if-< $power-of-2?:abort/disp32
14306     # var tmp/eax: int = n-1
14307     48/decrement-eax
14308     # var tmp2/eax: int = n & tmp
14309     23/and-> *(ebp+8) 0/r32/eax
14310     # return (tmp2 == 0)
14311     3d/compare-eax-and 0/imm32
14312     0f 94/set-byte-if-= %al
14313     81 4/subop/and %eax 0xff/imm32
14314 $power-of-2?:end:
14315     # . epilogue
14316     89/<- %esp 5/r32/ebp
14317     5d/pop-to-ebp
14318     c3/return
14319 
14320 $power-of-2?:abort:
14321     (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
14322     (flush *(ebp+0xc))
14323     (stop *(ebp+0x10) 1)
14324     # never gets here
14325 
14326 num-shift-rights:  # n: int -> result/eax: int
14327     # precondition: n is a positive power of 2
14328     # . prologue
14329     55/push-ebp
14330     89/<- %ebp 4/r32/esp
14331     # . save registers
14332     51/push-ecx
14333     # var curr/ecx: int = n
14334     8b/-> *(ebp+8) 1/r32/ecx
14335     # result = 0
14336     b8/copy-to-eax 0/imm32
14337     {
14338       # if (curr <= 1) break
14339       81 7/subop/compare %ecx 1/imm32
14340       7e/jump-if-<= break/disp8
14341       40/increment-eax
14342       c1/shift 5/subop/arithmetic-right %ecx 1/imm8
14343       eb/jump loop/disp8
14344     }
14345 $num-shift-rights:end:
14346     # . restore registers
14347     59/pop-to-ecx
14348     # . epilogue
14349     89/<- %esp 5/r32/ebp
14350     5d/pop-to-ebp
14351     c3/return
14352 
14353 mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
14354     # . prologue
14355     55/push-ebp
14356     89/<- %ebp 4/r32/esp
14357     # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
14358     8b/-> *(ebp+8) 0/r32/eax
14359     (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
14360     (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
14361     # var output-var/eax: (addr var) = second-inout->value
14362     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
14363 #?     (write-buffered Stderr "mu-get-offset: ")
14364 #?     (write-int32-hex-buffered Stderr %eax)
14365 #?     (write-buffered Stderr " name: ")
14366 #?     50/push-eax
14367 #?     (lookup *eax *(eax+4))  # Var-name
14368 #?     (write-buffered Stderr %eax)
14369 #?     58/pop-to-eax
14370 #?     (write-buffered Stderr Newline)
14371 #?     (flush Stderr)
14372     # return output-var->stack-offset
14373     8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
14374 #?     (write-buffered Stderr "=> ")
14375 #?     (write-int32-hex-buffered Stderr %eax)
14376 #?     (write-buffered Stderr Newline)
14377 #?     (flush Stderr)
14378 $emit-get-offset:end:
14379     # . epilogue
14380     89/<- %esp 5/r32/ebp
14381     5d/pop-to-ebp
14382     c3/return
14383 
14384 emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
14385     # . prologue
14386     55/push-ebp
14387     89/<- %ebp 4/r32/esp
14388     # . save registers
14389     50/push-eax
14390     51/push-ecx
14391     56/push-esi
14392     # esi = block
14393     8b/-> *(ebp+0xc) 6/r32/esi
14394     # block->var->block-depth = *Curr-block-depth
14395     (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
14396     8b/-> *Curr-block-depth 1/r32/ecx
14397     89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
14398     # var stmts/eax: (addr list stmt) = lookup(block->statements)
14399     (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
14400     #
14401     {
14402 $emit-subx-block:check-empty:
14403       3d/compare-eax-and 0/imm32
14404       0f 84/jump-if-= break/disp32
14405       (emit-indent *(ebp+8) *Curr-block-depth)
14406       (write-buffered *(ebp+8) "{\n")
14407       # var v/ecx: (addr var) = lookup(block->var)
14408       (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
14409       89/<- %ecx 0/r32/eax
14410       #
14411       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14412       (write-buffered *(ebp+8) %eax)
14413       (write-buffered *(ebp+8) ":loop:\n")
14414       ff 0/subop/increment *Curr-block-depth
14415       (push *(ebp+0x10) *(esi+0xc))  # Block-var
14416       (push *(ebp+0x10) *(esi+0x10))  # Block-var
14417       (push *(ebp+0x10) 0)  # false
14418       # emit block->statements
14419       (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
14420       (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
14421       (pop *(ebp+0x10))  # => eax
14422       (pop *(ebp+0x10))  # => eax
14423       (pop *(ebp+0x10))  # => eax
14424       ff 1/subop/decrement *Curr-block-depth
14425       (emit-indent *(ebp+8) *Curr-block-depth)
14426       (write-buffered *(ebp+8) "}\n")
14427       (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
14428       (write-buffered *(ebp+8) %eax)
14429       (write-buffered *(ebp+8) ":break:\n")
14430     }
14431 $emit-subx-block:end:
14432     # . restore registers
14433     5e/pop-to-esi
14434     59/pop-to-ecx
14435     58/pop-to-eax
14436     # . epilogue
14437     89/<- %esp 5/r32/ebp
14438     5d/pop-to-ebp
14439     c3/return
14440 
14441 # Primitives supported
14442 # See mu_instructions for a summary of this linked-list data structure.
14443 #
14444 # For each operation, put variants with hard-coded registers before flexible ones.
14445 #
14446 # Unfortunately, our restrictions on addresses require that various fields in
14447 # primitives be handles, which complicates these definitions.
14448 #   - we need to insert dummy fields all over the place for fake alloc-ids
14449 #   - we can't use our syntax sugar of quoted literals for string fields
14450 #
14451 # Fake alloc-ids are needed because our type definitions up top require
14452 # handles but it's clearer to statically allocate these long-lived objects.
14453 # Fake alloc-ids are perfectly safe, but they can't be reclaimed.
14454 #
14455 # Every 'object' below starts with a fake alloc-id. It may also contain other
14456 # fake alloc-ids for various handle fields.
14457 #
14458 # I think of objects starting with a fake alloc-id as having type 'payload'.
14459 # It's not really intended to be created dynamically; for that use `allocate`
14460 # as usual.
14461 #
14462 # Idea for a notation to simplify such definitions:
14463 #   _Primitive-increment-eax:  # (payload primitive)
14464 #     0x11/alloc-id:fake:payload
14465 #     0x11 @(0x11 "increment")  # name
14466 #     0 0                       # inouts
14467 #     0x11 @(0x11/payload
14468 #            0x11 @(0x11/payload  # List-value
14469 #                   0 0             # Var-name
14470 #                   0x11 @(0x11     # Var-type
14471 #                          1/is-atom
14472 #                          1/value 0/unused   # Type-tree-left
14473 #                          0 0                # Type-tree-right
14474 #                         )
14475 #                   1               # block-depth
14476 #                   0               # stack-offset
14477 #                   0x11 @(0x11 "eax")  # Var-register
14478 #                  )
14479 #            0 0)                 # List-next
14480 #     ...
14481 #     _Primitive-increment-ecx/imm32/next
14482 #   ...
14483 # Awfully complex and non-obvious. But also clearly signals there's something
14484 # to learn here, so may be worth trying.
14485 #
14486 # '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
14487 #
14488 # For now we'll continue to just use comments and manually ensure they stay up
14489 # to date.
14490 == data
14491 Primitives:  # (addr primitive)
14492 # - increment/decrement
14493 _Primitive-increment-eax:  # (addr primitive)
14494     # var/eax <- increment => 40/increment-eax
14495     0x11/imm32/alloc-id:fake
14496     _string-increment/imm32/name
14497     0/imm32/no-inouts
14498     0/imm32/no-inouts
14499     0x11/imm32/alloc-id:fake
14500     Single-int-var-in-eax/imm32/outputs
14501     0x11/imm32/alloc-id:fake
14502     _string_40_increment_eax/imm32/subx-name
14503     0/imm32/no-rm32
14504     0/imm32/no-r32
14505     0/imm32/no-imm32
14506     0/imm32/no-disp32
14507     0/imm32/output-is-write-only
14508     0x11/imm32/alloc-id:fake
14509     _Primitive-increment-ecx/imm32/next
14510 _Primitive-increment-ecx:  # (payload primitive)
14511     0x11/imm32/alloc-id:fake:payload
14512     # var/ecx <- increment => 41/increment-ecx
14513     0x11/imm32/alloc-id:fake
14514     _string-increment/imm32/name
14515     0/imm32/no-inouts
14516     0/imm32/no-inouts
14517     0x11/imm32/alloc-id:fake
14518     Single-int-var-in-ecx/imm32/outputs
14519     0x11/imm32/alloc-id:fake
14520     _string_41_increment_ecx/imm32/subx-name
14521     0/imm32/no-rm32
14522     0/imm32/no-r32
14523     0/imm32/no-imm32
14524     0/imm32/no-disp32
14525     0/imm32/output-is-write-only
14526     0x11/imm32/alloc-id:fake
14527     _Primitive-increment-edx/imm32/next
14528 _Primitive-increment-edx:  # (payload primitive)
14529     0x11/imm32/alloc-id:fake:payload
14530     # var/edx <- increment => 42/increment-edx
14531     0x11/imm32/alloc-id:fake
14532     _string-increment/imm32/name
14533     0/imm32/no-inouts
14534     0/imm32/no-inouts
14535     0x11/imm32/alloc-id:fake
14536     Single-int-var-in-edx/imm32/outputs
14537     0x11/imm32/alloc-id:fake
14538     _string_42_increment_edx/imm32/subx-name
14539     0/imm32/no-rm32
14540     0/imm32/no-r32
14541     0/imm32/no-imm32
14542     0/imm32/no-disp32
14543     0/imm32/output-is-write-only
14544     0x11/imm32/alloc-id:fake
14545     _Primitive-increment-ebx/imm32/next
14546 _Primitive-increment-ebx:  # (payload primitive)
14547     0x11/imm32/alloc-id:fake:payload
14548     # var/ebx <- increment => 43/increment-ebx
14549     0x11/imm32/alloc-id:fake
14550     _string-increment/imm32/name
14551     0/imm32/no-inouts
14552     0/imm32/no-inouts
14553     0x11/imm32/alloc-id:fake
14554     Single-int-var-in-ebx/imm32/outputs
14555     0x11/imm32/alloc-id:fake
14556     _string_43_increment_ebx/imm32/subx-name
14557     0/imm32/no-rm32
14558     0/imm32/no-r32
14559     0/imm32/no-imm32
14560     0/imm32/no-disp32
14561     0/imm32/output-is-write-only
14562     0x11/imm32/alloc-id:fake
14563     _Primitive-increment-esi/imm32/next
14564 _Primitive-increment-esi:  # (payload primitive)
14565     0x11/imm32/alloc-id:fake:payload
14566     # var/esi <- increment => 46/increment-esi
14567     0x11/imm32/alloc-id:fake
14568     _string-increment/imm32/name
14569     0/imm32/no-inouts
14570     0/imm32/no-inouts
14571     0x11/imm32/alloc-id:fake
14572     Single-int-var-in-esi/imm32/outputs
14573     0x11/imm32/alloc-id:fake
14574     _string_46_increment_esi/imm32/subx-name
14575     0/imm32/no-rm32
14576     0/imm32/no-r32
14577     0/imm32/no-imm32
14578     0/imm32/no-disp32
14579     0/imm32/output-is-write-only
14580     0x11/imm32/alloc-id:fake
14581     _Primitive-increment-edi/imm32/next
14582 _Primitive-increment-edi:  # (payload primitive)
14583     0x11/imm32/alloc-id:fake:payload
14584     # var/edi <- increment => 47/increment-edi
14585     0x11/imm32/alloc-id:fake
14586     _string-increment/imm32/name
14587     0/imm32/no-inouts
14588     0/imm32/no-inouts
14589     0x11/imm32/alloc-id:fake
14590     Single-int-var-in-edi/imm32/outputs
14591     0x11/imm32/alloc-id:fake
14592     _string_47_increment_edi/imm32/subx-name
14593     0/imm32/no-rm32
14594     0/imm32/no-r32
14595     0/imm32/no-imm32
14596     0/imm32/no-disp32
14597     0/imm32/output-is-write-only
14598     0x11/imm32/alloc-id:fake
14599     _Primitive-decrement-eax/imm32/next
14600 _Primitive-decrement-eax:  # (payload primitive)
14601     0x11/imm32/alloc-id:fake:payload
14602     # var/eax <- decrement => 48/decrement-eax
14603     0x11/imm32/alloc-id:fake
14604     _string-decrement/imm32/name
14605     0/imm32/no-inouts
14606     0/imm32/no-inouts
14607     0x11/imm32/alloc-id:fake
14608     Single-int-var-in-eax/imm32/outputs
14609     0x11/imm32/alloc-id:fake
14610     _string_48_decrement_eax/imm32/subx-name
14611     0/imm32/no-rm32
14612     0/imm32/no-r32
14613     0/imm32/no-imm32
14614     0/imm32/no-disp32
14615     0/imm32/output-is-write-only
14616     0x11/imm32/alloc-id:fake
14617     _Primitive-decrement-ecx/imm32/next
14618 _Primitive-decrement-ecx:  # (payload primitive)
14619     0x11/imm32/alloc-id:fake:payload
14620     # var/ecx <- decrement => 49/decrement-ecx
14621     0x11/imm32/alloc-id:fake
14622     _string-decrement/imm32/name
14623     0/imm32/no-inouts
14624     0/imm32/no-inouts
14625     0x11/imm32/alloc-id:fake
14626     Single-int-var-in-ecx/imm32/outputs
14627     0x11/imm32/alloc-id:fake
14628     _string_49_decrement_ecx/imm32/subx-name
14629     0/imm32/no-rm32
14630     0/imm32/no-r32
14631     0/imm32/no-imm32
14632     0/imm32/no-disp32
14633     0/imm32/output-is-write-only
14634     0x11/imm32/alloc-id:fake
14635     _Primitive-decrement-edx/imm32/next
14636 _Primitive-decrement-edx:  # (payload primitive)
14637     0x11/imm32/alloc-id:fake:payload
14638     # var/edx <- decrement => 4a/decrement-edx
14639     0x11/imm32/alloc-id:fake
14640     _string-decrement/imm32/name
14641     0/imm32/no-inouts
14642     0/imm32/no-inouts
14643     0x11/imm32/alloc-id:fake
14644     Single-int-var-in-edx/imm32/outputs
14645     0x11/imm32/alloc-id:fake
14646     _string_4a_decrement_edx/imm32/subx-name
14647     0/imm32/no-rm32
14648     0/imm32/no-r32
14649     0/imm32/no-imm32
14650     0/imm32/no-disp32
14651     0/imm32/output-is-write-only
14652     0x11/imm32/alloc-id:fake
14653     _Primitive-decrement-ebx/imm32/next
14654 _Primitive-decrement-ebx:  # (payload primitive)
14655     0x11/imm32/alloc-id:fake:payload
14656     # var/ebx <- decrement => 4b/decrement-ebx
14657     0x11/imm32/alloc-id:fake
14658     _string-decrement/imm32/name
14659     0/imm32/no-inouts
14660     0/imm32/no-inouts
14661     0x11/imm32/alloc-id:fake
14662     Single-int-var-in-ebx/imm32/outputs
14663     0x11/imm32/alloc-id:fake
14664     _string_4b_decrement_ebx/imm32/subx-name
14665     0/imm32/no-rm32
14666     0/imm32/no-r32
14667     0/imm32/no-imm32
14668     0/imm32/no-disp32
14669     0/imm32/output-is-write-only
14670     0x11/imm32/alloc-id:fake
14671     _Primitive-decrement-esi/imm32/next
14672 _Primitive-decrement-esi:  # (payload primitive)
14673     0x11/imm32/alloc-id:fake:payload
14674     # var/esi <- decrement => 4e/decrement-esi
14675     0x11/imm32/alloc-id:fake
14676     _string-decrement/imm32/name
14677     0/imm32/no-inouts
14678     0/imm32/no-inouts
14679     0x11/imm32/alloc-id:fake
14680     Single-int-var-in-esi/imm32/outputs
14681     0x11/imm32/alloc-id:fake
14682     _string_4e_decrement_esi/imm32/subx-name
14683     0/imm32/no-rm32
14684     0/imm32/no-r32
14685     0/imm32/no-imm32
14686     0/imm32/no-disp32
14687     0/imm32/output-is-write-only
14688     0x11/imm32/alloc-id:fake
14689     _Primitive-decrement-edi/imm32/next
14690 _Primitive-decrement-edi:  # (payload primitive)
14691     0x11/imm32/alloc-id:fake:payload
14692     # var/edi <- decrement => 4f/decrement-edi
14693     0x11/imm32/alloc-id:fake
14694     _string-decrement/imm32/name
14695     0/imm32/no-inouts
14696     0/imm32/no-inouts
14697     0x11/imm32/alloc-id:fake
14698     Single-int-var-in-edi/imm32/outputs
14699     0x11/imm32/alloc-id:fake
14700     _string_4f_decrement_edi/imm32/subx-name
14701     0/imm32/no-rm32
14702     0/imm32/no-r32
14703     0/imm32/no-imm32
14704     0/imm32/no-disp32
14705     0/imm32/output-is-write-only
14706     0x11/imm32/alloc-id:fake
14707     _Primitive-increment-mem/imm32/next
14708 _Primitive-increment-mem:  # (payload primitive)
14709     0x11/imm32/alloc-id:fake:payload
14710     # increment var => ff 0/subop/increment *(ebp+__)
14711     0x11/imm32/alloc-id:fake
14712     _string-increment/imm32/name
14713     0x11/imm32/alloc-id:fake
14714     Single-int-var-in-mem/imm32/inouts
14715     0/imm32/no-outputs
14716     0/imm32/no-outputs
14717     0x11/imm32/alloc-id:fake
14718     _string_ff_subop_increment/imm32/subx-name
14719     1/imm32/rm32-is-first-inout
14720     0/imm32/no-r32
14721     0/imm32/no-imm32
14722     0/imm32/no-disp32
14723     0/imm32/output-is-write-only
14724     0x11/imm32/alloc-id:fake
14725     _Primitive-increment-reg/imm32/next
14726 _Primitive-increment-reg:  # (payload primitive)
14727     0x11/imm32/alloc-id:fake:payload
14728     # var/reg <- increment => ff 0/subop/increment %__
14729     0x11/imm32/alloc-id:fake
14730     _string-increment/imm32/name
14731     0/imm32/no-inouts
14732     0/imm32/no-inouts
14733     0x11/imm32/alloc-id:fake
14734     Single-int-var-in-some-register/imm32/outputs
14735     0x11/imm32/alloc-id:fake
14736     _string_ff_subop_increment/imm32/subx-name
14737     3/imm32/rm32-is-first-output
14738     0/imm32/no-r32
14739     0/imm32/no-imm32
14740     0/imm32/no-disp32
14741     0/imm32/output-is-write-only
14742     0x11/imm32/alloc-id:fake
14743     _Primitive-decrement-mem/imm32/next
14744 _Primitive-decrement-mem:  # (payload primitive)
14745     0x11/imm32/alloc-id:fake:payload
14746     # decrement var => ff 1/subop/decrement *(ebp+__)
14747     0x11/imm32/alloc-id:fake
14748     _string-decrement/imm32/name
14749     0x11/imm32/alloc-id:fake
14750     Single-int-var-in-mem/imm32/inouts
14751     0/imm32/no-outputs
14752     0/imm32/no-outputs
14753     0x11/imm32/alloc-id:fake
14754     _string_ff_subop_decrement/imm32/subx-name
14755     1/imm32/rm32-is-first-inout
14756     0/imm32/no-r32
14757     0/imm32/no-imm32
14758     0/imm32/no-disp32
14759     0/imm32/output-is-write-only
14760     0x11/imm32/alloc-id:fake
14761     _Primitive-decrement-reg/imm32/next
14762 _Primitive-decrement-reg:  # (payload primitive)
14763     0x11/imm32/alloc-id:fake:payload
14764     # var/reg <- decrement => ff 1/subop/decrement %__
14765     0x11/imm32/alloc-id:fake
14766     _string-decrement/imm32/name
14767     0/imm32/no-inouts
14768     0/imm32/no-inouts
14769     0x11/imm32/alloc-id:fake
14770     Single-int-var-in-some-register/imm32/outputs
14771     0x11/imm32/alloc-id:fake
14772     _string_ff_subop_decrement/imm32/subx-name
14773     3/imm32/rm32-is-first-output
14774     0/imm32/no-r32
14775     0/imm32/no-imm32
14776     0/imm32/no-disp32
14777     0/imm32/output-is-write-only
14778     0x11/imm32/alloc-id:fake
14779     _Primitive-add-to-eax/imm32/next
14780 # - add
14781 _Primitive-add-to-eax:  # (payload primitive)
14782     0x11/imm32/alloc-id:fake:payload
14783     # var/eax <- add lit => 05/add-to-eax lit/imm32
14784     0x11/imm32/alloc-id:fake
14785     _string-add/imm32/name
14786     0x11/imm32/alloc-id:fake
14787     Single-lit-var/imm32/inouts
14788     0x11/imm32/alloc-id:fake
14789     Single-int-var-in-eax/imm32/outputs
14790     0x11/imm32/alloc-id:fake
14791     _string_05_add_to_eax/imm32/subx-name
14792     0/imm32/no-rm32
14793     0/imm32/no-r32
14794     1/imm32/imm32-is-first-inout
14795     0/imm32/no-disp32
14796     0/imm32/output-is-write-only
14797     0x11/imm32/alloc-id:fake
14798     _Primitive-add-reg-to-reg/imm32/next
14799 _Primitive-add-reg-to-reg:  # (payload primitive)
14800     0x11/imm32/alloc-id:fake:payload
14801     # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
14802     0x11/imm32/alloc-id:fake
14803     _string-add/imm32/name
14804     0x11/imm32/alloc-id:fake
14805     Single-int-var-in-some-register/imm32/inouts
14806     0x11/imm32/alloc-id:fake
14807     Single-int-var-in-some-register/imm32/outputs
14808     0x11/imm32/alloc-id:fake
14809     _string_01_add_to/imm32/subx-name
14810     3/imm32/rm32-is-first-output
14811     1/imm32/r32-is-first-inout
14812     0/imm32/no-imm32
14813     0/imm32/no-disp32
14814     0/imm32/output-is-write-only
14815     0x11/imm32/alloc-id:fake
14816     _Primitive-add-reg-to-mem/imm32/next
14817 _Primitive-add-reg-to-mem:  # (payload primitive)
14818     0x11/imm32/alloc-id:fake:payload
14819     # add-to var1 var2/reg => 01/add-to var1 var2/r32
14820     0x11/imm32/alloc-id:fake
14821     _string-add-to/imm32/name
14822     0x11/imm32/alloc-id:fake
14823     Two-args-int-stack-int-reg/imm32/inouts
14824     0/imm32/no-outputs
14825     0/imm32/no-outputs
14826     0x11/imm32/alloc-id:fake
14827     _string_01_add_to/imm32/subx-name
14828     1/imm32/rm32-is-first-inout
14829     2/imm32/r32-is-second-inout
14830     0/imm32/no-imm32
14831     0/imm32/no-disp32
14832     0/imm32/output-is-write-only
14833     0x11/imm32/alloc-id:fake
14834     _Primitive-add-mem-to-reg/imm32/next
14835 _Primitive-add-mem-to-reg:  # (payload primitive)
14836     0x11/imm32/alloc-id:fake:payload
14837     # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
14838     0x11/imm32/alloc-id:fake
14839     _string-add/imm32/name
14840     0x11/imm32/alloc-id:fake
14841     Single-int-var-in-mem/imm32/inouts
14842     0x11/imm32/alloc-id:fake
14843     Single-int-var-in-some-register/imm32/outputs
14844     0x11/imm32/alloc-id:fake
14845     _string_03_add/imm32/subx-name
14846     1/imm32/rm32-is-first-inout
14847     3/imm32/r32-is-first-output
14848     0/imm32/no-imm32
14849     0/imm32/no-disp32
14850     0/imm32/output-is-write-only
14851     0x11/imm32/alloc-id:fake
14852     _Primitive-add-lit-to-reg/imm32/next
14853 _Primitive-add-lit-to-reg:  # (payload primitive)
14854     0x11/imm32/alloc-id:fake:payload
14855     # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
14856     0x11/imm32/alloc-id:fake
14857     _string-add/imm32/name
14858     0x11/imm32/alloc-id:fake
14859     Single-lit-var/imm32/inouts
14860     0x11/imm32/alloc-id:fake
14861     Single-int-var-in-some-register/imm32/outputs
14862     0x11/imm32/alloc-id:fake
14863     _string_81_subop_add/imm32/subx-name
14864     3/imm32/rm32-is-first-output
14865     0/imm32/no-r32
14866     1/imm32/imm32-is-first-inout
14867     0/imm32/no-disp32
14868     0/imm32/output-is-write-only
14869     0x11/imm32/alloc-id:fake
14870     _Primitive-add-lit-to-mem/imm32/next
14871 _Primitive-add-lit-to-mem:  # (payload primitive)
14872     0x11/imm32/alloc-id:fake:payload
14873     # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
14874     0x11/imm32/alloc-id:fake
14875     _string-add-to/imm32/name
14876     0x11/imm32/alloc-id:fake
14877     Int-var-and-literal/imm32/inouts
14878     0/imm32/no-outputs
14879     0/imm32/no-outputs
14880     0x11/imm32/alloc-id:fake
14881     _string_81_subop_add/imm32/subx-name
14882     1/imm32/rm32-is-first-inout
14883     0/imm32/no-r32
14884     2/imm32/imm32-is-second-inout
14885     0/imm32/no-disp32
14886     0/imm32/output-is-write-only
14887     0x11/imm32/alloc-id:fake
14888     _Primitive-subtract-from-eax/imm32/next
14889 # - subtract
14890 _Primitive-subtract-from-eax:  # (payload primitive)
14891     0x11/imm32/alloc-id:fake:payload
14892     # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
14893     0x11/imm32/alloc-id:fake
14894     _string-subtract/imm32/name
14895     0x11/imm32/alloc-id:fake
14896     Single-lit-var/imm32/inouts
14897     0x11/imm32/alloc-id:fake
14898     Single-int-var-in-eax/imm32/outputs
14899     0x11/imm32/alloc-id:fake
14900     _string_2d_subtract_from_eax/imm32/subx-name
14901     0/imm32/no-rm32
14902     0/imm32/no-r32
14903     1/imm32/imm32-is-first-inout
14904     0/imm32/no-disp32
14905     0/imm32/output-is-write-only
14906     0x11/imm32/alloc-id:fake
14907     _Primitive-subtract-reg-from-reg/imm32/next
14908 _Primitive-subtract-reg-from-reg:  # (payload primitive)
14909     0x11/imm32/alloc-id:fake:payload
14910     # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
14911     0x11/imm32/alloc-id:fake
14912     _string-subtract/imm32/name
14913     0x11/imm32/alloc-id:fake
14914     Single-int-var-in-some-register/imm32/inouts
14915     0x11/imm32/alloc-id:fake
14916     Single-int-var-in-some-register/imm32/outputs
14917     0x11/imm32/alloc-id:fake
14918     _string_29_subtract_from/imm32/subx-name
14919     3/imm32/rm32-is-first-output
14920     1/imm32/r32-is-first-inout
14921     0/imm32/no-imm32
14922     0/imm32/no-disp32
14923     0/imm32/output-is-write-only
14924     0x11/imm32/alloc-id:fake
14925     _Primitive-subtract-reg-from-mem/imm32/next
14926 _Primitive-subtract-reg-from-mem:  # (payload primitive)
14927     0x11/imm32/alloc-id:fake:payload
14928     # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
14929     0x11/imm32/alloc-id:fake
14930     _string-subtract-from/imm32/name
14931     0x11/imm32/alloc-id:fake
14932     Two-args-int-stack-int-reg/imm32/inouts
14933     0/imm32/no-outputs
14934     0/imm32/no-outputs
14935     0x11/imm32/alloc-id:fake
14936     _string_29_subtract_from/imm32/subx-name
14937     1/imm32/rm32-is-first-inout
14938     2/imm32/r32-is-second-inout
14939     0/imm32/no-imm32
14940     0/imm32/no-disp32
14941     0/imm32/output-is-write-only
14942     0x11/imm32/alloc-id:fake
14943     _Primitive-subtract-mem-from-reg/imm32/next
14944 _Primitive-subtract-mem-from-reg:  # (payload primitive)
14945     0x11/imm32/alloc-id:fake:payload
14946     # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
14947     0x11/imm32/alloc-id:fake
14948     _string-subtract/imm32/name
14949     0x11/imm32/alloc-id:fake
14950     Single-int-var-in-mem/imm32/inouts
14951     0x11/imm32/alloc-id:fake
14952     Single-int-var-in-some-register/imm32/outputs
14953     0x11/imm32/alloc-id:fake
14954     _string_2b_subtract/imm32/subx-name
14955     1/imm32/rm32-is-first-inout
14956     3/imm32/r32-is-first-output
14957     0/imm32/no-imm32
14958     0/imm32/no-disp32
14959     0/imm32/output-is-write-only
14960     0x11/imm32/alloc-id:fake
14961     _Primitive-subtract-lit-from-reg/imm32/next
14962 _Primitive-subtract-lit-from-reg:  # (payload primitive)
14963     0x11/imm32/alloc-id:fake:payload
14964     # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
14965     0x11/imm32/alloc-id:fake
14966     _string-subtract/imm32/name
14967     0x11/imm32/alloc-id:fake
14968     Single-lit-var/imm32/inouts
14969     0x11/imm32/alloc-id:fake
14970     Single-int-var-in-some-register/imm32/outputs
14971     0x11/imm32/alloc-id:fake
14972     _string_81_subop_subtract/imm32/subx-name
14973     3/imm32/rm32-is-first-output
14974     0/imm32/no-r32
14975     1/imm32/imm32-is-first-inout
14976     0/imm32/no-disp32
14977     0/imm32/output-is-write-only
14978     0x11/imm32/alloc-id:fake
14979     _Primitive-subtract-lit-from-mem/imm32/next
14980 _Primitive-subtract-lit-from-mem:  # (payload primitive)
14981     0x11/imm32/alloc-id:fake:payload
14982     # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
14983     0x11/imm32/alloc-id:fake
14984     _string-subtract-from/imm32/name
14985     0x11/imm32/alloc-id:fake
14986     Int-var-and-literal/imm32/inouts
14987     0/imm32/no-outputs
14988     0/imm32/no-outputs
14989     0x11/imm32/alloc-id:fake
14990     _string_81_subop_subtract/imm32/subx-name
14991     1/imm32/rm32-is-first-inout
14992     0/imm32/no-r32
14993     2/imm32/imm32-is-first-inout
14994     0/imm32/no-disp32
14995     0/imm32/output-is-write-only
14996     0x11/imm32/alloc-id:fake
14997     _Primitive-and-with-eax/imm32/next
14998 # - and
14999 _Primitive-and-with-eax:  # (payload primitive)
15000     0x11/imm32/alloc-id:fake:payload
15001     # var/eax <- and lit => 25/and-with-eax lit/imm32
15002     0x11/imm32/alloc-id:fake
15003     _string-and/imm32/name
15004     0x11/imm32/alloc-id:fake
15005     Single-lit-var/imm32/inouts
15006     0x11/imm32/alloc-id:fake
15007     Single-int-var-in-eax/imm32/outputs
15008     0x11/imm32/alloc-id:fake
15009     _string_25_and_with_eax/imm32/subx-name
15010     0/imm32/no-rm32
15011     0/imm32/no-r32
15012     1/imm32/imm32-is-first-inout
15013     0/imm32/no-disp32
15014     0/imm32/output-is-write-only
15015     0x11/imm32/alloc-id:fake
15016     _Primitive-and-reg-with-reg/imm32/next
15017 _Primitive-and-reg-with-reg:  # (payload primitive)
15018     0x11/imm32/alloc-id:fake:payload
15019     # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
15020     0x11/imm32/alloc-id:fake
15021     _string-and/imm32/name
15022     0x11/imm32/alloc-id:fake
15023     Single-int-var-in-some-register/imm32/inouts
15024     0x11/imm32/alloc-id:fake
15025     Single-int-var-in-some-register/imm32/outputs
15026     0x11/imm32/alloc-id:fake
15027     _string_21_and_with/imm32/subx-name
15028     3/imm32/rm32-is-first-output
15029     1/imm32/r32-is-first-inout
15030     0/imm32/no-imm32
15031     0/imm32/no-disp32
15032     0/imm32/output-is-write-only
15033     0x11/imm32/alloc-id:fake
15034     _Primitive-and-reg-with-mem/imm32/next
15035 _Primitive-and-reg-with-mem:  # (payload primitive)
15036     0x11/imm32/alloc-id:fake:payload
15037     # and-with var1 var2/reg => 21/and-with var1 var2/r32
15038     0x11/imm32/alloc-id:fake
15039     _string-and-with/imm32/name
15040     0x11/imm32/alloc-id:fake
15041     Two-args-int-stack-int-reg/imm32/inouts
15042     0/imm32/no-outputs
15043     0/imm32/no-outputs
15044     0x11/imm32/alloc-id:fake
15045     _string_21_and_with/imm32/subx-name
15046     1/imm32/rm32-is-first-inout
15047     2/imm32/r32-is-second-inout
15048     0/imm32/no-imm32
15049     0/imm32/no-disp32
15050     0/imm32/output-is-write-only
15051     0x11/imm32/alloc-id:fake
15052     _Primitive-and-mem-with-reg/imm32/next
15053 _Primitive-and-mem-with-reg:  # (payload primitive)
15054     0x11/imm32/alloc-id:fake:payload
15055     # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
15056     0x11/imm32/alloc-id:fake
15057     _string-and/imm32/name
15058     0x11/imm32/alloc-id:fake
15059     Single-int-var-in-mem/imm32/inouts
15060     0x11/imm32/alloc-id:fake
15061     Single-int-var-in-some-register/imm32/outputs
15062     0x11/imm32/alloc-id:fake
15063     _string_23_and/imm32/subx-name
15064     1/imm32/rm32-is-first-inout
15065     3/imm32/r32-is-first-output
15066     0/imm32/no-imm32
15067     0/imm32/no-disp32
15068     0/imm32/output-is-write-only
15069     0x11/imm32/alloc-id:fake
15070     _Primitive-and-lit-with-reg/imm32/next
15071 _Primitive-and-lit-with-reg:  # (payload primitive)
15072     0x11/imm32/alloc-id:fake:payload
15073     # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
15074     0x11/imm32/alloc-id:fake
15075     _string-and/imm32/name
15076     0x11/imm32/alloc-id:fake
15077     Single-lit-var/imm32/inouts
15078     0x11/imm32/alloc-id:fake
15079     Single-int-var-in-some-register/imm32/outputs
15080     0x11/imm32/alloc-id:fake
15081     _string_81_subop_and/imm32/subx-name
15082     3/imm32/rm32-is-first-output
15083     0/imm32/no-r32
15084     1/imm32/imm32-is-first-inout
15085     0/imm32/no-disp32
15086     0/imm32/output-is-write-only
15087     0x11/imm32/alloc-id:fake
15088     _Primitive-and-lit-with-mem/imm32/next
15089 _Primitive-and-lit-with-mem:  # (payload primitive)
15090     0x11/imm32/alloc-id:fake:payload
15091     # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
15092     0x11/imm32/alloc-id:fake
15093     _string-and-with/imm32/name
15094     0x11/imm32/alloc-id:fake
15095     Int-var-and-literal/imm32/inouts
15096     0/imm32/no-outputs
15097     0/imm32/no-outputs
15098     0x11/imm32/alloc-id:fake
15099     _string_81_subop_and/imm32/subx-name
15100     1/imm32/rm32-is-first-inout
15101     0/imm32/no-r32
15102     2/imm32/imm32-is-first-inout
15103     0/imm32/no-disp32
15104     0/imm32/output-is-write-only
15105     0x11/imm32/alloc-id:fake
15106     _Primitive-or-with-eax/imm32/next
15107 # - or
15108 _Primitive-or-with-eax:  # (payload primitive)
15109     0x11/imm32/alloc-id:fake:payload
15110     # var/eax <- or lit => 0d/or-with-eax lit/imm32
15111     0x11/imm32/alloc-id:fake
15112     _string-or/imm32/name
15113     0x11/imm32/alloc-id:fake
15114     Single-lit-var/imm32/inouts
15115     0x11/imm32/alloc-id:fake
15116     Single-int-var-in-eax/imm32/outputs
15117     0x11/imm32/alloc-id:fake
15118     _string_0d_or_with_eax/imm32/subx-name
15119     0/imm32/no-rm32
15120     0/imm32/no-r32
15121     1/imm32/imm32-is-first-inout
15122     0/imm32/no-disp32
15123     0/imm32/output-is-write-only
15124     0x11/imm32/alloc-id:fake
15125     _Primitive-or-reg-with-reg/imm32/next
15126 _Primitive-or-reg-with-reg:  # (payload primitive)
15127     0x11/imm32/alloc-id:fake:payload
15128     # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
15129     0x11/imm32/alloc-id:fake
15130     _string-or/imm32/name
15131     0x11/imm32/alloc-id:fake
15132     Single-int-var-in-some-register/imm32/inouts
15133     0x11/imm32/alloc-id:fake
15134     Single-int-var-in-some-register/imm32/outputs
15135     0x11/imm32/alloc-id:fake
15136     _string_09_or_with/imm32/subx-name
15137     3/imm32/rm32-is-first-output
15138     1/imm32/r32-is-first-inout
15139     0/imm32/no-imm32
15140     0/imm32/no-disp32
15141     0/imm32/output-is-write-only
15142     0x11/imm32/alloc-id:fake
15143     _Primitive-or-reg-with-mem/imm32/next
15144 _Primitive-or-reg-with-mem:  # (payload primitive)
15145     0x11/imm32/alloc-id:fake:payload
15146     # or-with var1 var2/reg => 09/or-with var1 var2/r32
15147     0x11/imm32/alloc-id:fake
15148     _string-or-with/imm32/name
15149     0x11/imm32/alloc-id:fake
15150     Two-args-int-stack-int-reg/imm32/inouts
15151     0/imm32/no-outputs
15152     0/imm32/no-outputs
15153     0x11/imm32/alloc-id:fake
15154     _string_09_or_with/imm32/subx-name
15155     1/imm32/rm32-is-first-inout
15156     2/imm32/r32-is-second-inout
15157     0/imm32/no-imm32
15158     0/imm32/no-disp32
15159     0/imm32/output-is-write-only
15160     0x11/imm32/alloc-id:fake
15161     _Primitive-or-mem-with-reg/imm32/next
15162 _Primitive-or-mem-with-reg:  # (payload primitive)
15163     0x11/imm32/alloc-id:fake:payload
15164     # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
15165     0x11/imm32/alloc-id:fake
15166     _string-or/imm32/name
15167     0x11/imm32/alloc-id:fake
15168     Single-int-var-in-mem/imm32/inouts
15169     0x11/imm32/alloc-id:fake
15170     Single-int-var-in-some-register/imm32/outputs
15171     0x11/imm32/alloc-id:fake
15172     _string_0b_or/imm32/subx-name
15173     1/imm32/rm32-is-first-inout
15174     3/imm32/r32-is-first-output
15175     0/imm32/no-imm32
15176     0/imm32/no-disp32
15177     0/imm32/output-is-write-only
15178     0x11/imm32/alloc-id:fake
15179     _Primitive-or-lit-with-reg/imm32/next
15180 _Primitive-or-lit-with-reg:  # (payload primitive)
15181     0x11/imm32/alloc-id:fake:payload
15182     # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
15183     0x11/imm32/alloc-id:fake
15184     _string-or/imm32/name
15185     0x11/imm32/alloc-id:fake
15186     Single-lit-var/imm32/inouts
15187     0x11/imm32/alloc-id:fake
15188     Single-int-var-in-some-register/imm32/outputs
15189     0x11/imm32/alloc-id:fake
15190     _string_81_subop_or/imm32/subx-name
15191     3/imm32/rm32-is-first-output
15192     0/imm32/no-r32
15193     1/imm32/imm32-is-first-inout
15194     0/imm32/no-disp32
15195     0/imm32/output-is-write-only
15196     0x11/imm32/alloc-id:fake
15197     _Primitive-or-lit-with-mem/imm32/next
15198 _Primitive-or-lit-with-mem:  # (payload primitive)
15199     0x11/imm32/alloc-id:fake:payload
15200     # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
15201     0x11/imm32/alloc-id:fake
15202     _string-or-with/imm32/name
15203     0x11/imm32/alloc-id:fake
15204     Int-var-and-literal/imm32/inouts
15205     0/imm32/no-outputs
15206     0/imm32/no-outputs
15207     0x11/imm32/alloc-id:fake
15208     _string_81_subop_or/imm32/subx-name
15209     1/imm32/rm32-is-first-inout
15210     0/imm32/no-r32
15211     2/imm32/imm32-is-second-inout
15212     0/imm32/no-disp32
15213     0/imm32/output-is-write-only
15214     0x11/imm32/alloc-id:fake
15215     _Primitive-xor-with-eax/imm32/next
15216 # - xor
15217 _Primitive-xor-with-eax:  # (payload primitive)
15218     0x11/imm32/alloc-id:fake:payload
15219     # var/eax <- xor lit => 35/xor-with-eax lit/imm32
15220     0x11/imm32/alloc-id:fake
15221     _string-xor/imm32/name
15222     0x11/imm32/alloc-id:fake
15223     Single-lit-var/imm32/inouts
15224     0x11/imm32/alloc-id:fake
15225     Single-int-var-in-eax/imm32/outputs
15226     0x11/imm32/alloc-id:fake
15227     _string_35_xor_with_eax/imm32/subx-name
15228     0/imm32/no-rm32
15229     0/imm32/no-r32
15230     1/imm32/imm32-is-first-inout
15231     0/imm32/no-disp32
15232     0/imm32/output-is-write-only
15233     0x11/imm32/alloc-id:fake
15234     _Primitive-xor-reg-with-reg/imm32/next
15235 _Primitive-xor-reg-with-reg:  # (payload primitive)
15236     0x11/imm32/alloc-id:fake:payload
15237     # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
15238     0x11/imm32/alloc-id:fake
15239     _string-xor/imm32/name
15240     0x11/imm32/alloc-id:fake
15241     Single-int-var-in-some-register/imm32/inouts
15242     0x11/imm32/alloc-id:fake
15243     Single-int-var-in-some-register/imm32/outputs
15244     0x11/imm32/alloc-id:fake
15245     _string_31_xor_with/imm32/subx-name
15246     3/imm32/rm32-is-first-output
15247     1/imm32/r32-is-first-inout
15248     0/imm32/no-imm32
15249     0/imm32/no-disp32
15250     0/imm32/output-is-write-only
15251     0x11/imm32/alloc-id:fake
15252     _Primitive-xor-reg-with-mem/imm32/next
15253 _Primitive-xor-reg-with-mem:  # (payload primitive)
15254     0x11/imm32/alloc-id:fake:payload
15255     # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
15256     0x11/imm32/alloc-id:fake
15257     _string-xor-with/imm32/name
15258     0x11/imm32/alloc-id:fake
15259     Two-args-int-stack-int-reg/imm32/inouts
15260     0/imm32/no-outputs
15261     0/imm32/no-outputs
15262     0x11/imm32/alloc-id:fake
15263     _string_31_xor_with/imm32/subx-name
15264     1/imm32/rm32-is-first-inout
15265     2/imm32/r32-is-second-inout
15266     0/imm32/no-imm32
15267     0/imm32/no-disp32
15268     0/imm32/output-is-write-only
15269     0x11/imm32/alloc-id:fake
15270     _Primitive-xor-mem-with-reg/imm32/next
15271 _Primitive-xor-mem-with-reg:  # (payload primitive)
15272     0x11/imm32/alloc-id:fake:payload
15273     # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
15274     0x11/imm32/alloc-id:fake
15275     _string-xor/imm32/name
15276     0x11/imm32/alloc-id:fake
15277     Single-int-var-in-mem/imm32/inouts
15278     0x11/imm32/alloc-id:fake
15279     Single-int-var-in-some-register/imm32/outputs
15280     0x11/imm32/alloc-id:fake
15281     _string_33_xor/imm32/subx-name
15282     1/imm32/rm32-is-first-inout
15283     3/imm32/r32-is-first-output
15284     0/imm32/no-imm32
15285     0/imm32/no-disp32
15286     0/imm32/output-is-write-only
15287     0x11/imm32/alloc-id:fake
15288     _Primitive-xor-lit-with-reg/imm32/next
15289 _Primitive-xor-lit-with-reg:  # (payload primitive)
15290     0x11/imm32/alloc-id:fake:payload
15291     # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
15292     0x11/imm32/alloc-id:fake
15293     _string-xor/imm32/name
15294     0x11/imm32/alloc-id:fake
15295     Single-lit-var/imm32/inouts
15296     0x11/imm32/alloc-id:fake
15297     Single-int-var-in-some-register/imm32/outputs
15298     0x11/imm32/alloc-id:fake
15299     _string_81_subop_xor/imm32/subx-name
15300     3/imm32/rm32-is-first-output
15301     0/imm32/no-r32
15302     1/imm32/imm32-is-first-inout
15303     0/imm32/no-disp32
15304     0/imm32/output-is-write-only
15305     0x11/imm32/alloc-id:fake
15306     _Primitive-xor-lit-with-mem/imm32/next
15307 _Primitive-xor-lit-with-mem:  # (payload primitive)
15308     0x11/imm32/alloc-id:fake:payload
15309     # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
15310     0x11/imm32/alloc-id:fake
15311     _string-xor-with/imm32/name
15312     0x11/imm32/alloc-id:fake
15313     Int-var-and-literal/imm32/inouts
15314     0/imm32/no-outputs
15315     0/imm32/no-outputs
15316     0x11/imm32/alloc-id:fake
15317     _string_81_subop_xor/imm32/subx-name
15318     1/imm32/rm32-is-first-inout
15319     0/imm32/no-r32
15320     2/imm32/imm32-is-first-inout
15321     0/imm32/no-disp32
15322     0/imm32/output-is-write-only
15323     0x11/imm32/alloc-id:fake
15324     _Primitive-copy-to-eax/imm32/next
15325 # - copy
15326 _Primitive-copy-to-eax:  # (payload primitive)
15327     0x11/imm32/alloc-id:fake:payload
15328     # var/eax <- copy lit => b8/copy-to-eax lit/imm32
15329     0x11/imm32/alloc-id:fake
15330     _string-copy/imm32/name
15331     0x11/imm32/alloc-id:fake
15332     Single-lit-var/imm32/inouts
15333     0x11/imm32/alloc-id:fake
15334     Single-int-var-in-eax/imm32/outputs
15335     0x11/imm32/alloc-id:fake
15336     _string_b8_copy_to_eax/imm32/subx-name
15337     0/imm32/no-rm32
15338     0/imm32/no-r32
15339     1/imm32/imm32-is-first-inout
15340     0/imm32/no-disp32
15341     1/imm32/output-is-write-only
15342     0x11/imm32/alloc-id:fake
15343     _Primitive-copy-to-ecx/imm32/next
15344 _Primitive-copy-to-ecx:  # (payload primitive)
15345     0x11/imm32/alloc-id:fake:payload
15346     # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
15347     0x11/imm32/alloc-id:fake
15348     _string-copy/imm32/name
15349     0x11/imm32/alloc-id:fake
15350     Single-lit-var/imm32/inouts
15351     0x11/imm32/alloc-id:fake
15352     Single-int-var-in-ecx/imm32/outputs
15353     0x11/imm32/alloc-id:fake
15354     _string_b9_copy_to_ecx/imm32/subx-name
15355     0/imm32/no-rm32
15356     0/imm32/no-r32
15357     1/imm32/imm32-is-first-inout
15358     0/imm32/no-disp32
15359     1/imm32/output-is-write-only
15360     0x11/imm32/alloc-id:fake
15361     _Primitive-copy-to-edx/imm32/next
15362 _Primitive-copy-to-edx:  # (payload primitive)
15363     0x11/imm32/alloc-id:fake:payload
15364     # var/edx <- copy lit => ba/copy-to-edx lit/imm32
15365     0x11/imm32/alloc-id:fake
15366     _string-copy/imm32/name
15367     0x11/imm32/alloc-id:fake
15368     Single-lit-var/imm32/inouts
15369     0x11/imm32/alloc-id:fake
15370     Single-int-var-in-edx/imm32/outputs
15371     0x11/imm32/alloc-id:fake
15372     _string_ba_copy_to_edx/imm32/subx-name
15373     0/imm32/no-rm32
15374     0/imm32/no-r32
15375     1/imm32/imm32-is-first-inout
15376     0/imm32/no-disp32
15377     1/imm32/output-is-write-only
15378     0x11/imm32/alloc-id:fake
15379     _Primitive-copy-to-ebx/imm32/next
15380 _Primitive-copy-to-ebx:  # (payload primitive)
15381     0x11/imm32/alloc-id:fake:payload
15382     # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
15383     0x11/imm32/alloc-id:fake
15384     _string-copy/imm32/name
15385     0x11/imm32/alloc-id:fake
15386     Single-lit-var/imm32/inouts
15387     0x11/imm32/alloc-id:fake
15388     Single-int-var-in-ebx/imm32/outputs
15389     0x11/imm32/alloc-id:fake
15390     _string_bb_copy_to_ebx/imm32/subx-name
15391     0/imm32/no-rm32
15392     0/imm32/no-r32
15393     1/imm32/imm32-is-first-inout
15394     0/imm32/no-disp32
15395     1/imm32/output-is-write-only
15396     0x11/imm32/alloc-id:fake
15397     _Primitive-copy-to-esi/imm32/next
15398 _Primitive-copy-to-esi:  # (payload primitive)
15399     0x11/imm32/alloc-id:fake:payload
15400     # var/esi <- copy lit => be/copy-to-esi lit/imm32
15401     0x11/imm32/alloc-id:fake
15402     _string-copy/imm32/name
15403     0x11/imm32/alloc-id:fake
15404     Single-lit-var/imm32/inouts
15405     0x11/imm32/alloc-id:fake
15406     Single-int-var-in-esi/imm32/outputs
15407     0x11/imm32/alloc-id:fake
15408     _string_be_copy_to_esi/imm32/subx-name
15409     0/imm32/no-rm32
15410     0/imm32/no-r32
15411     1/imm32/imm32-is-first-inout
15412     0/imm32/no-disp32
15413     1/imm32/output-is-write-only
15414     0x11/imm32/alloc-id:fake
15415     _Primitive-copy-to-edi/imm32/next
15416 _Primitive-copy-to-edi:  # (payload primitive)
15417     0x11/imm32/alloc-id:fake:payload
15418     # var/edi <- copy lit => bf/copy-to-edi lit/imm32
15419     0x11/imm32/alloc-id:fake
15420     _string-copy/imm32/name
15421     0x11/imm32/alloc-id:fake
15422     Single-lit-var/imm32/inouts
15423     0x11/imm32/alloc-id:fake
15424     Single-int-var-in-edi/imm32/outputs
15425     0x11/imm32/alloc-id:fake
15426     _string_bf_copy_to_edi/imm32/subx-name
15427     0/imm32/no-rm32
15428     0/imm32/no-r32
15429     1/imm32/imm32-is-first-inout
15430     0/imm32/no-disp32
15431     1/imm32/output-is-write-only
15432     0x11/imm32/alloc-id:fake
15433     _Primitive-copy-reg-to-reg/imm32/next
15434 _Primitive-copy-reg-to-reg:  # (payload primitive)
15435     0x11/imm32/alloc-id:fake:payload
15436     # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
15437     0x11/imm32/alloc-id:fake
15438     _string-copy/imm32/name
15439     0x11/imm32/alloc-id:fake
15440     Single-int-var-in-some-register/imm32/inouts
15441     0x11/imm32/alloc-id:fake
15442     Single-int-var-in-some-register/imm32/outputs
15443     0x11/imm32/alloc-id:fake
15444     _string_89_<-/imm32/subx-name
15445     3/imm32/rm32-is-first-output
15446     1/imm32/r32-is-first-inout
15447     0/imm32/no-imm32
15448     0/imm32/no-disp32
15449     1/imm32/output-is-write-only
15450     0x11/imm32/alloc-id:fake
15451     _Primitive-copy-reg-to-mem/imm32/next
15452 _Primitive-copy-reg-to-mem:  # (payload primitive)
15453     0x11/imm32/alloc-id:fake:payload
15454     # copy-to var1 var2/reg => 89/<- var1 var2/r32
15455     0x11/imm32/alloc-id:fake
15456     _string-copy-to/imm32/name
15457     0x11/imm32/alloc-id:fake
15458     Two-args-int-stack-int-reg/imm32/inouts
15459     0/imm32/no-outputs
15460     0/imm32/no-outputs
15461     0x11/imm32/alloc-id:fake
15462     _string_89_<-/imm32/subx-name
15463     1/imm32/rm32-is-first-inout
15464     2/imm32/r32-is-second-inout
15465     0/imm32/no-imm32
15466     0/imm32/no-disp32
15467     1/imm32/output-is-write-only
15468     0x11/imm32/alloc-id:fake
15469     _Primitive-copy-mem-to-reg/imm32/next
15470 _Primitive-copy-mem-to-reg:  # (payload primitive)
15471     0x11/imm32/alloc-id:fake:payload
15472     # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
15473     0x11/imm32/alloc-id:fake
15474     _string-copy/imm32/name
15475     0x11/imm32/alloc-id:fake
15476     Single-int-var-in-mem/imm32/inouts
15477     0x11/imm32/alloc-id:fake
15478     Single-int-var-in-some-register/imm32/outputs
15479     0x11/imm32/alloc-id:fake
15480     _string_8b_->/imm32/subx-name
15481     1/imm32/rm32-is-first-inout
15482     3/imm32/r32-is-first-output
15483     0/imm32/no-imm32
15484     0/imm32/no-disp32
15485     1/imm32/output-is-write-only
15486     0x11/imm32/alloc-id:fake
15487     _Primitive-copy-lit-to-reg/imm32/next
15488 _Primitive-copy-lit-to-reg:  # (payload primitive)
15489     0x11/imm32/alloc-id:fake:payload
15490     # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
15491     0x11/imm32/alloc-id:fake
15492     _string-copy/imm32/name
15493     0x11/imm32/alloc-id:fake
15494     Single-lit-var/imm32/inouts
15495     0x11/imm32/alloc-id:fake
15496     Single-int-var-in-some-register/imm32/outputs
15497     0x11/imm32/alloc-id:fake
15498     _string_c7_subop_copy/imm32/subx-name
15499     3/imm32/rm32-is-first-output
15500     0/imm32/no-r32
15501     1/imm32/imm32-is-first-inout
15502     0/imm32/no-disp32
15503     1/imm32/output-is-write-only
15504     0x11/imm32/alloc-id:fake
15505     _Primitive-copy-lit-to-mem/imm32/next
15506 _Primitive-copy-lit-to-mem:  # (payload primitive)
15507     0x11/imm32/alloc-id:fake:payload
15508     # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
15509     0x11/imm32/alloc-id:fake
15510     _string-copy-to/imm32/name
15511     0x11/imm32/alloc-id:fake
15512     Int-var-and-literal/imm32/inouts
15513     0/imm32/no-outputs
15514     0/imm32/no-outputs
15515     0x11/imm32/alloc-id:fake
15516     _string_c7_subop_copy/imm32/subx-name
15517     1/imm32/rm32-is-first-inout
15518     0/imm32/no-r32
15519     2/imm32/imm32-is-first-inout
15520     0/imm32/no-disp32
15521     1/imm32/output-is-write-only
15522     0x11/imm32/alloc-id:fake
15523     _Primitive-copy-byte-from-reg/imm32/next
15524 # - copy byte
15525 _Primitive-copy-byte-from-reg:
15526     0x11/imm32/alloc-id:fake:payload
15527     # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
15528     0x11/imm32/alloc-id:fake
15529     _string-copy-byte/imm32/name
15530     0x11/imm32/alloc-id:fake
15531     Single-byte-var-in-some-register/imm32/inouts
15532     0x11/imm32/alloc-id:fake
15533     Single-byte-var-in-some-register/imm32/outputs
15534     0x11/imm32/alloc-id:fake
15535     _string_8a_copy_byte/imm32/subx-name
15536     1/imm32/rm32-is-first-inout
15537     3/imm32/r32-is-first-output
15538     0/imm32/no-imm32
15539     0/imm32/no-disp32
15540     1/imm32/output-is-write-only
15541     0x11/imm32/alloc-id:fake
15542     _Primitive-copy-byte-from-mem/imm32/next
15543 _Primitive-copy-byte-from-mem:
15544     0x11/imm32/alloc-id:fake:payload
15545     # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
15546     0x11/imm32/alloc-id:fake
15547     _string-copy-byte/imm32/name
15548     0x11/imm32/alloc-id:fake
15549     Single-byte-var-in-mem/imm32/inouts
15550     0x11/imm32/alloc-id:fake
15551     Single-byte-var-in-some-register/imm32/outputs
15552     0x11/imm32/alloc-id:fake
15553     _string_8a_copy_byte/imm32/subx-name
15554     1/imm32/rm32-is-first-inout
15555     3/imm32/r32-is-first-output
15556     0/imm32/no-imm32
15557     0/imm32/no-disp32
15558     1/imm32/output-is-write-only
15559     0x11/imm32/alloc-id:fake
15560     _Primitive-copy-byte-to-mem/imm32/next
15561 _Primitive-copy-byte-to-mem:
15562     0x11/imm32/alloc-id:fake:payload
15563     # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
15564     0x11/imm32/alloc-id:fake
15565     _string-copy-byte-to/imm32/name
15566     0x11/imm32/alloc-id:fake
15567     Two-args-byte-stack-byte-reg/imm32/inouts
15568     0/imm32/no-outputs
15569     0/imm32/no-outputs
15570     0x11/imm32/alloc-id:fake
15571     _string_88_copy_byte/imm32/subx-name
15572     1/imm32/rm32-is-first-inout
15573     2/imm32/r32-is-second-inout
15574     0/imm32/no-imm32
15575     0/imm32/no-disp32
15576     0/imm32/output-is-write-only
15577     0x11/imm32/alloc-id:fake
15578     _Primitive-address/imm32/next
15579 # - address
15580 _Primitive-address:  # (payload primitive)
15581     0x11/imm32/alloc-id:fake:payload
15582     # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
15583     0x11/imm32/alloc-id:fake
15584     _string-address/imm32/name
15585     0x11/imm32/alloc-id:fake
15586     Single-int-var-in-mem/imm32/inouts
15587     0x11/imm32/alloc-id:fake
15588     Single-addr-var-in-some-register/imm32/outputs
15589     0x11/imm32/alloc-id:fake
15590     _string_8d_copy_address/imm32/subx-name
15591     1/imm32/rm32-is-first-inout
15592     3/imm32/r32-is-first-output
15593     0/imm32/no-imm32
15594     0/imm32/no-disp32
15595     1/imm32/output-is-write-only
15596     0x11/imm32/alloc-id:fake
15597     _Primitive-compare-reg-with-reg/imm32/next
15598 # - compare
15599 _Primitive-compare-reg-with-reg:  # (payload primitive)
15600     0x11/imm32/alloc-id:fake:payload
15601     # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
15602     0x11/imm32/alloc-id:fake
15603     _string-compare/imm32/name
15604     0x11/imm32/alloc-id:fake
15605     Two-int-args-in-regs/imm32/inouts
15606     0/imm32/no-outputs
15607     0/imm32/no-outputs
15608     0x11/imm32/alloc-id:fake
15609     _string_39_compare->/imm32/subx-name
15610     1/imm32/rm32-is-first-inout
15611     2/imm32/r32-is-second-inout
15612     0/imm32/no-imm32
15613     0/imm32/no-disp32
15614     0/imm32/output-is-write-only
15615     0x11/imm32/alloc-id:fake
15616     _Primitive-compare-mem-with-reg/imm32/next
15617 _Primitive-compare-mem-with-reg:  # (payload primitive)
15618     0x11/imm32/alloc-id:fake:payload
15619     # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
15620     0x11/imm32/alloc-id:fake
15621     _string-compare/imm32/name
15622     0x11/imm32/alloc-id:fake
15623     Two-args-int-stack-int-reg/imm32/inouts
15624     0/imm32/no-outputs
15625     0/imm32/no-outputs
15626     0x11/imm32/alloc-id:fake
15627     _string_39_compare->/imm32/subx-name
15628     1/imm32/rm32-is-first-inout
15629     2/imm32/r32-is-second-inout
15630     0/imm32/no-imm32
15631     0/imm32/no-disp32
15632     0/imm32/output-is-write-only
15633     0x11/imm32/alloc-id:fake
15634     _Primitive-compare-reg-with-mem/imm32/next
15635 _Primitive-compare-reg-with-mem:  # (payload primitive)
15636     0x11/imm32/alloc-id:fake:payload
15637     # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
15638     0x11/imm32/alloc-id:fake
15639     _string-compare/imm32/name
15640     0x11/imm32/alloc-id:fake
15641     Two-args-int-reg-int-stack/imm32/inouts
15642     0/imm32/no-outputs
15643     0/imm32/no-outputs
15644     0x11/imm32/alloc-id:fake
15645     _string_3b_compare<-/imm32/subx-name
15646     2/imm32/rm32-is-second-inout
15647     1/imm32/r32-is-first-inout
15648     0/imm32/no-imm32
15649     0/imm32/no-disp32
15650     0/imm32/output-is-write-only
15651     0x11/imm32/alloc-id:fake
15652     _Primitive-compare-eax-with-literal/imm32/next
15653 _Primitive-compare-eax-with-literal:  # (payload primitive)
15654     0x11/imm32/alloc-id:fake:payload
15655     # compare var1/eax n => 3d/compare-eax-with n/imm32
15656     0x11/imm32/alloc-id:fake
15657     _string-compare/imm32/name
15658     0x11/imm32/alloc-id:fake
15659     Two-args-int-eax-int-literal/imm32/inouts
15660     0/imm32/no-outputs
15661     0/imm32/no-outputs
15662     0x11/imm32/alloc-id:fake
15663     _string_3d_compare_eax_with/imm32/subx-name
15664     0/imm32/no-rm32
15665     0/imm32/no-r32
15666     2/imm32/imm32-is-second-inout
15667     0/imm32/no-disp32
15668     0/imm32/output-is-write-only
15669     0x11/imm32/alloc-id:fake
15670     _Primitive-compare-reg-with-literal/imm32/next
15671 _Primitive-compare-reg-with-literal:  # (payload primitive)
15672     0x11/imm32/alloc-id:fake:payload
15673     # compare var1/reg n => 81 7/subop/compare %reg n/imm32
15674     0x11/imm32/alloc-id:fake
15675     _string-compare/imm32/name
15676     0x11/imm32/alloc-id:fake
15677     Int-var-in-register-and-literal/imm32/inouts
15678     0/imm32/no-outputs
15679     0/imm32/no-outputs
15680     0x11/imm32/alloc-id:fake
15681     _string_81_subop_compare/imm32/subx-name
15682     1/imm32/rm32-is-first-inout
15683     0/imm32/no-r32
15684     2/imm32/imm32-is-second-inout
15685     0/imm32/no-disp32
15686     0/imm32/output-is-write-only
15687     0x11/imm32/alloc-id:fake
15688     _Primitive-compare-mem-with-literal/imm32/next
15689 _Primitive-compare-mem-with-literal:  # (payload primitive)
15690     0x11/imm32/alloc-id:fake:payload
15691     # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
15692     0x11/imm32/alloc-id:fake
15693     _string-compare/imm32/name
15694     0x11/imm32/alloc-id:fake
15695     Int-var-and-literal/imm32/inouts
15696     0/imm32/no-outputs
15697     0/imm32/no-outputs
15698     0x11/imm32/alloc-id:fake
15699     _string_81_subop_compare/imm32/subx-name
15700     1/imm32/rm32-is-first-inout
15701     0/imm32/no-r32
15702     2/imm32/imm32-is-second-inout
15703     0/imm32/no-disp32
15704     0/imm32/output-is-write-only
15705     0x11/imm32/alloc-id:fake
15706     _Primitive-multiply-reg-by-reg/imm32/next
15707 # - multiply
15708 _Primitive-multiply-reg-by-reg:  # (payload primitive)
15709     0x11/imm32/alloc-id:fake:payload
15710     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
15711     0x11/imm32/alloc-id:fake
15712     _string-multiply/imm32/name
15713     0x11/imm32/alloc-id:fake
15714     Single-int-var-in-some-register/imm32/inouts
15715     0x11/imm32/alloc-id:fake
15716     Single-int-var-in-some-register/imm32/outputs
15717     0x11/imm32/alloc-id:fake
15718     _string_0f_af_multiply/imm32/subx-name
15719     1/imm32/rm32-is-first-inout
15720     3/imm32/r32-is-first-output
15721     0/imm32/no-imm32
15722     0/imm32/no-disp32
15723     0/imm32/output-is-write-only
15724     0x11/imm32/alloc-id:fake
15725     _Primitive-multiply-reg-by-mem/imm32/next
15726 _Primitive-multiply-reg-by-mem:  # (payload primitive)
15727     0x11/imm32/alloc-id:fake:payload
15728     # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
15729     0x11/imm32/alloc-id:fake
15730     _string-multiply/imm32/name
15731     0x11/imm32/alloc-id:fake
15732     Single-int-var-in-mem/imm32/inouts
15733     0x11/imm32/alloc-id:fake
15734     Single-int-var-in-some-register/imm32/outputs
15735     0x11/imm32/alloc-id:fake
15736     _string_0f_af_multiply/imm32/subx-name
15737     1/imm32/rm32-is-first-inout
15738     3/imm32/r32-is-first-output
15739     0/imm32/no-imm32
15740     0/imm32/no-disp32
15741     0/imm32/output-is-write-only
15742     0x11/imm32/alloc-id:fake
15743     _Primitive-break-if-addr</imm32/next
15744 # - branches
15745 _Primitive-break-if-addr<:  # (payload primitive)
15746     0x11/imm32/alloc-id:fake:payload
15747     0x11/imm32/alloc-id:fake
15748     _string-break-if-addr</imm32/name
15749     0/imm32/no-inouts
15750     0/imm32/no-inouts
15751     0/imm32/no-outputs
15752     0/imm32/no-outputs
15753     0x11/imm32/alloc-id:fake
15754     _string_0f_82_jump_break/imm32/subx-name
15755     0/imm32/no-rm32
15756     0/imm32/no-r32
15757     0/imm32/no-imm32
15758     0/imm32/no-disp32
15759     0/imm32/no-output
15760     0x11/imm32/alloc-id:fake
15761     _Primitive-break-if-addr>=/imm32/next
15762 _Primitive-break-if-addr>=:  # (payload primitive)
15763     0x11/imm32/alloc-id:fake:payload
15764     0x11/imm32/alloc-id:fake
15765     _string-break-if-addr>=/imm32/name
15766     0/imm32/no-inouts
15767     0/imm32/no-inouts
15768     0/imm32/no-outputs
15769     0/imm32/no-outputs
15770     0x11/imm32/alloc-id:fake
15771     _string_0f_83_jump_break/imm32/subx-name
15772     0/imm32/no-rm32
15773     0/imm32/no-r32
15774     0/imm32/no-imm32
15775     0/imm32/no-disp32
15776     0/imm32/no-output
15777     0x11/imm32/alloc-id:fake
15778     _Primitive-break-if-=/imm32/next
15779 _Primitive-break-if-=:  # (payload primitive)
15780     0x11/imm32/alloc-id:fake:payload
15781     0x11/imm32/alloc-id:fake
15782     _string-break-if-=/imm32/name
15783     0/imm32/no-inouts
15784     0/imm32/no-inouts
15785     0/imm32/no-outputs
15786     0/imm32/no-outputs
15787     0x11/imm32/alloc-id:fake
15788     _string_0f_84_jump_break/imm32/subx-name
15789     0/imm32/no-rm32
15790     0/imm32/no-r32
15791     0/imm32/no-imm32
15792     0/imm32/no-disp32
15793     0/imm32/no-output
15794     0x11/imm32/alloc-id:fake
15795     _Primitive-break-if-!=/imm32/next
15796 _Primitive-break-if-!=:  # (payload primitive)
15797     0x11/imm32/alloc-id:fake:payload
15798     0x11/imm32/alloc-id:fake
15799     _string-break-if-!=/imm32/name
15800     0/imm32/no-inouts
15801     0/imm32/no-inouts
15802     0/imm32/no-outputs
15803     0/imm32/no-outputs
15804     0x11/imm32/alloc-id:fake
15805     _string_0f_85_jump_break/imm32/subx-name
15806     0/imm32/no-rm32
15807     0/imm32/no-r32
15808     0/imm32/no-imm32
15809     0/imm32/no-disp32
15810     0/imm32/no-output
15811     0x11/imm32/alloc-id:fake
15812     _Primitive-break-if-addr<=/imm32/next
15813 _Primitive-break-if-addr<=:  # (payload primitive)
15814     0x11/imm32/alloc-id:fake:payload
15815     0x11/imm32/alloc-id:fake
15816     _string-break-if-addr<=/imm32/name
15817     0/imm32/no-inouts
15818     0/imm32/no-inouts
15819     0/imm32/no-outputs
15820     0/imm32/no-outputs
15821     0x11/imm32/alloc-id:fake
15822     _string_0f_86_jump_break/imm32/subx-name
15823     0/imm32/no-rm32
15824     0/imm32/no-r32
15825     0/imm32/no-imm32
15826     0/imm32/no-disp32
15827     0/imm32/no-output
15828     0x11/imm32/alloc-id:fake
15829     _Primitive-break-if-addr>/imm32/next
15830 _Primitive-break-if-addr>:  # (payload primitive)
15831     0x11/imm32/alloc-id:fake:payload
15832     0x11/imm32/alloc-id:fake
15833     _string-break-if-addr>/imm32/name
15834     0/imm32/no-inouts
15835     0/imm32/no-inouts
15836     0/imm32/no-outputs
15837     0/imm32/no-outputs
15838     0x11/imm32/alloc-id:fake
15839     _string_0f_87_jump_break/imm32/subx-name
15840     0/imm32/no-rm32
15841     0/imm32/no-r32
15842     0/imm32/no-imm32
15843     0/imm32/no-disp32
15844     0/imm32/no-output
15845     0x11/imm32/alloc-id:fake
15846     _Primitive-break-if-</imm32/next
15847 _Primitive-break-if-<:  # (payload primitive)
15848     0x11/imm32/alloc-id:fake:payload
15849     0x11/imm32/alloc-id:fake
15850     _string-break-if-</imm32/name
15851     0/imm32/no-inouts
15852     0/imm32/no-inouts
15853     0/imm32/no-outputs
15854     0/imm32/no-outputs
15855     0x11/imm32/alloc-id:fake
15856     _string_0f_8c_jump_break/imm32/subx-name
15857     0/imm32/no-rm32
15858     0/imm32/no-r32
15859     0/imm32/no-imm32
15860     0/imm32/no-disp32
15861     0/imm32/no-output
15862     0x11/imm32/alloc-id:fake
15863     _Primitive-break-if->=/imm32/next
15864 _Primitive-break-if->=:  # (payload primitive)
15865     0x11/imm32/alloc-id:fake:payload
15866     0x11/imm32/alloc-id:fake
15867     _string-break-if->=/imm32/name
15868     0/imm32/no-inouts
15869     0/imm32/no-inouts
15870     0/imm32/no-outputs
15871     0/imm32/no-outputs
15872     0x11/imm32/alloc-id:fake
15873     _string_0f_8d_jump_break/imm32/subx-name
15874     0/imm32/no-rm32
15875     0/imm32/no-r32
15876     0/imm32/no-imm32
15877     0/imm32/no-disp32
15878     0/imm32/no-output
15879     0x11/imm32/alloc-id:fake
15880     _Primitive-break-if-<=/imm32/next
15881 _Primitive-break-if-<=:  # (payload primitive)
15882     0x11/imm32/alloc-id:fake:payload
15883     0x11/imm32/alloc-id:fake
15884     _string-break-if-<=/imm32/name
15885     0/imm32/no-inouts
15886     0/imm32/no-inouts
15887     0/imm32/no-outputs
15888     0/imm32/no-outputs
15889     0x11/imm32/alloc-id:fake
15890     _string_0f_8e_jump_break/imm32/subx-name
15891     0/imm32/no-rm32
15892     0/imm32/no-r32
15893     0/imm32/no-imm32
15894     0/imm32/no-disp32
15895     0/imm32/no-output
15896     0x11/imm32/alloc-id:fake
15897     _Primitive-break-if->/imm32/next
15898 _Primitive-break-if->:  # (payload primitive)
15899     0x11/imm32/alloc-id:fake:payload
15900     0x11/imm32/alloc-id:fake
15901     _string-break-if->/imm32/name
15902     0/imm32/no-inouts
15903     0/imm32/no-inouts
15904     0/imm32/no-outputs
15905     0/imm32/no-outputs
15906     0x11/imm32/alloc-id:fake
15907     _string_0f_8f_jump_break/imm32/subx-name
15908     0/imm32/no-rm32
15909     0/imm32/no-r32
15910     0/imm32/no-imm32
15911     0/imm32/no-disp32
15912     0/imm32/no-output
15913     0x11/imm32/alloc-id:fake
15914     _Primitive-break/imm32/next
15915 _Primitive-break:  # (payload primitive)
15916     0x11/imm32/alloc-id:fake:payload
15917     0x11/imm32/alloc-id:fake
15918     _string-break/imm32/name
15919     0/imm32/no-inouts
15920     0/imm32/no-inouts
15921     0/imm32/no-outputs
15922     0/imm32/no-outputs
15923     0x11/imm32/alloc-id:fake
15924     _string_e9_jump_break/imm32/subx-name
15925     0/imm32/no-rm32
15926     0/imm32/no-r32
15927     0/imm32/no-imm32
15928     0/imm32/no-disp32
15929     0/imm32/no-output
15930     0x11/imm32/alloc-id:fake
15931     _Primitive-loop-if-addr</imm32/next
15932 _Primitive-loop-if-addr<:  # (payload primitive)
15933     0x11/imm32/alloc-id:fake:payload
15934     0x11/imm32/alloc-id:fake
15935     _string-loop-if-addr</imm32/name
15936     0/imm32/no-inouts
15937     0/imm32/no-inouts
15938     0/imm32/no-outputs
15939     0/imm32/no-outputs
15940     0x11/imm32/alloc-id:fake
15941     _string_0f_82_jump_loop/imm32/subx-name
15942     0/imm32/no-rm32
15943     0/imm32/no-r32
15944     0/imm32/no-imm32
15945     0/imm32/no-disp32
15946     0/imm32/no-output
15947     0x11/imm32/alloc-id:fake
15948     _Primitive-loop-if-addr>=/imm32/next
15949 _Primitive-loop-if-addr>=:  # (payload primitive)
15950     0x11/imm32/alloc-id:fake:payload
15951     0x11/imm32/alloc-id:fake
15952     _string-loop-if-addr>=/imm32/name
15953     0/imm32/no-inouts
15954     0/imm32/no-inouts
15955     0/imm32/no-outputs
15956     0/imm32/no-outputs
15957     0x11/imm32/alloc-id:fake
15958     _string_0f_83_jump_loop/imm32/subx-name
15959     0/imm32/no-rm32
15960     0/imm32/no-r32
15961     0/imm32/no-imm32
15962     0/imm32/no-disp32
15963     0/imm32/no-output
15964     0x11/imm32/alloc-id:fake
15965     _Primitive-loop-if-=/imm32/next
15966 _Primitive-loop-if-=:  # (payload primitive)
15967     0x11/imm32/alloc-id:fake:payload
15968     0x11/imm32/alloc-id:fake
15969     _string-loop-if-=/imm32/name
15970     0/imm32/no-inouts
15971     0/imm32/no-inouts
15972     0/imm32/no-outputs
15973     0/imm32/no-outputs
15974     0x11/imm32/alloc-id:fake
15975     _string_0f_84_jump_loop/imm32/subx-name
15976     0/imm32/no-rm32
15977     0/imm32/no-r32
15978     0/imm32/no-imm32
15979     0/imm32/no-disp32
15980     0/imm32/no-output
15981     0x11/imm32/alloc-id:fake
15982     _Primitive-loop-if-!=/imm32/next
15983 _Primitive-loop-if-!=:  # (payload primitive)
15984     0x11/imm32/alloc-id:fake:payload
15985     0x11/imm32/alloc-id:fake
15986     _string-loop-if-!=/imm32/name
15987     0/imm32/no-inouts
15988     0/imm32/no-inouts
15989     0/imm32/no-outputs
15990     0/imm32/no-outputs
15991     0x11/imm32/alloc-id:fake
15992     _string_0f_85_jump_loop/imm32/subx-name
15993     0/imm32/no-rm32
15994     0/imm32/no-r32
15995     0/imm32/no-imm32
15996     0/imm32/no-disp32
15997     0/imm32/no-output
15998     0x11/imm32/alloc-id:fake
15999     _Primitive-loop-if-addr<=/imm32/next
16000 _Primitive-loop-if-addr<=:  # (payload primitive)
16001     0x11/imm32/alloc-id:fake:payload
16002     0x11/imm32/alloc-id:fake
16003     _string-loop-if-addr<=/imm32/name
16004     0/imm32/no-inouts
16005     0/imm32/no-inouts
16006     0/imm32/no-outputs
16007     0/imm32/no-outputs
16008     0x11/imm32/alloc-id:fake
16009     _string_0f_86_jump_loop/imm32/subx-name
16010     0/imm32/no-rm32
16011     0/imm32/no-r32
16012     0/imm32/no-imm32
16013     0/imm32/no-disp32
16014     0/imm32/no-output
16015     0x11/imm32/alloc-id:fake
16016     _Primitive-loop-if-addr>/imm32/next
16017 _Primitive-loop-if-addr>:  # (payload primitive)
16018     0x11/imm32/alloc-id:fake:payload
16019     0x11/imm32/alloc-id:fake
16020     _string-loop-if-addr>/imm32/name
16021     0/imm32/no-inouts
16022     0/imm32/no-inouts
16023     0/imm32/no-outputs
16024     0/imm32/no-outputs
16025     0x11/imm32/alloc-id:fake
16026     _string_0f_87_jump_loop/imm32/subx-name
16027     0/imm32/no-rm32
16028     0/imm32/no-r32
16029     0/imm32/no-imm32
16030     0/imm32/no-disp32
16031     0/imm32/no-output
16032     0x11/imm32/alloc-id:fake
16033     _Primitive-loop-if-</imm32/next
16034 _Primitive-loop-if-<:  # (payload primitive)
16035     0x11/imm32/alloc-id:fake:payload
16036     0x11/imm32/alloc-id:fake
16037     _string-loop-if-</imm32/name
16038     0/imm32/no-inouts
16039     0/imm32/no-inouts
16040     0/imm32/no-outputs
16041     0/imm32/no-outputs
16042     0x11/imm32/alloc-id:fake
16043     _string_0f_8c_jump_loop/imm32/subx-name
16044     0/imm32/no-rm32
16045     0/imm32/no-r32
16046     0/imm32/no-imm32
16047     0/imm32/no-disp32
16048     0/imm32/no-output
16049     0x11/imm32/alloc-id:fake
16050     _Primitive-loop-if->=/imm32/next
16051 _Primitive-loop-if->=:  # (payload primitive)
16052     0x11/imm32/alloc-id:fake:payload
16053     0x11/imm32/alloc-id:fake
16054     _string-loop-if->=/imm32/name
16055     0/imm32/no-inouts
16056     0/imm32/no-inouts
16057     0/imm32/no-outputs
16058     0/imm32/no-outputs
16059     0x11/imm32/alloc-id:fake
16060     _string_0f_8d_jump_loop/imm32/subx-name
16061     0/imm32/no-rm32
16062     0/imm32/no-r32
16063     0/imm32/no-imm32
16064     0/imm32/no-disp32
16065     0/imm32/no-output
16066     0x11/imm32/alloc-id:fake
16067     _Primitive-loop-if-<=/imm32/next
16068 _Primitive-loop-if-<=:  # (payload primitive)
16069     0x11/imm32/alloc-id:fake:payload
16070     0x11/imm32/alloc-id:fake
16071     _string-loop-if-<=/imm32/name
16072     0/imm32/no-inouts
16073     0/imm32/no-inouts
16074     0/imm32/no-outputs
16075     0/imm32/no-outputs
16076     0x11/imm32/alloc-id:fake
16077     _string_0f_8e_jump_loop/imm32/subx-name
16078     0/imm32/no-rm32
16079     0/imm32/no-r32
16080     0/imm32/no-imm32
16081     0/imm32/no-disp32
16082     0/imm32/no-output
16083     0x11/imm32/alloc-id:fake
16084     _Primitive-loop-if->/imm32/next
16085 _Primitive-loop-if->:  # (payload primitive)
16086     0x11/imm32/alloc-id:fake:payload
16087     0x11/imm32/alloc-id:fake
16088     _string-loop-if->/imm32/name
16089     0/imm32/no-inouts
16090     0/imm32/no-inouts
16091     0/imm32/no-outputs
16092     0/imm32/no-outputs
16093     0x11/imm32/alloc-id:fake
16094     _string_0f_8f_jump_loop/imm32/subx-name
16095     0/imm32/no-rm32
16096     0/imm32/no-r32
16097     0/imm32/no-imm32
16098     0/imm32/no-disp32
16099     0/imm32/no-output
16100     0x11/imm32/alloc-id:fake
16101     _Primitive-loop/imm32/next  # we probably don't need an unconditional break
16102 _Primitive-loop:  # (payload primitive)
16103     0x11/imm32/alloc-id:fake:payload
16104     0x11/imm32/alloc-id:fake
16105     _string-loop/imm32/name
16106     0/imm32/no-inouts
16107     0/imm32/no-inouts
16108     0/imm32/no-outputs
16109     0/imm32/no-outputs
16110     0x11/imm32/alloc-id:fake
16111     _string_e9_jump_loop/imm32/subx-name
16112     0/imm32/no-rm32
16113     0/imm32/no-r32
16114     0/imm32/no-imm32
16115     0/imm32/no-disp32
16116     0/imm32/no-output
16117     0x11/imm32/alloc-id:fake
16118     _Primitive-break-if-addr<-named/imm32/next
16119 # - branches to named blocks
16120 _Primitive-break-if-addr<-named:  # (payload primitive)
16121     0x11/imm32/alloc-id:fake:payload
16122     0x11/imm32/alloc-id:fake
16123     _string-break-if-addr</imm32/name
16124     0x11/imm32/alloc-id:fake
16125     Single-lit-var/imm32/inouts
16126     0/imm32/no-outputs
16127     0/imm32/no-outputs
16128     0x11/imm32/alloc-id:fake
16129     _string_0f_82_jump_label/imm32/subx-name
16130     0/imm32/no-rm32
16131     0/imm32/no-r32
16132     0/imm32/no-imm32
16133     1/imm32/disp32-is-first-inout
16134     0/imm32/no-output
16135     0x11/imm32/alloc-id:fake
16136     _Primitive-break-if-addr>=-named/imm32/next
16137 _Primitive-break-if-addr>=-named:  # (payload primitive)
16138     0x11/imm32/alloc-id:fake:payload
16139     0x11/imm32/alloc-id:fake
16140     _string-break-if-addr>=/imm32/name
16141     0x11/imm32/alloc-id:fake
16142     Single-lit-var/imm32/inouts
16143     0/imm32/no-outputs
16144     0/imm32/no-outputs
16145     0x11/imm32/alloc-id:fake
16146     _string_0f_83_jump_label/imm32/subx-name
16147     0/imm32/no-rm32
16148     0/imm32/no-r32
16149     0/imm32/no-imm32
16150     1/imm32/disp32-is-first-inout
16151     0/imm32/no-output
16152     0x11/imm32/alloc-id:fake
16153     _Primitive-break-if-=-named/imm32/next
16154 _Primitive-break-if-=-named:  # (payload primitive)
16155     0x11/imm32/alloc-id:fake:payload
16156     0x11/imm32/alloc-id:fake
16157     _string-break-if-=/imm32/name
16158     0x11/imm32/alloc-id:fake
16159     Single-lit-var/imm32/inouts
16160     0/imm32/no-outputs
16161     0/imm32/no-outputs
16162     0x11/imm32/alloc-id:fake
16163     _string_0f_84_jump_label/imm32/subx-name
16164     0/imm32/no-rm32
16165     0/imm32/no-r32
16166     0/imm32/no-imm32
16167     1/imm32/disp32-is-first-inout
16168     0/imm32/no-output
16169     0x11/imm32/alloc-id:fake
16170     _Primitive-break-if-!=-named/imm32/next
16171 _Primitive-break-if-!=-named:  # (payload primitive)
16172     0x11/imm32/alloc-id:fake:payload
16173     0x11/imm32/alloc-id:fake
16174     _string-break-if-!=/imm32/name
16175     0x11/imm32/alloc-id:fake
16176     Single-lit-var/imm32/inouts
16177     0/imm32/no-outputs
16178     0/imm32/no-outputs
16179     0x11/imm32/alloc-id:fake
16180     _string_0f_85_jump_label/imm32/subx-name
16181     0/imm32/no-rm32
16182     0/imm32/no-r32
16183     0/imm32/no-imm32
16184     1/imm32/disp32-is-first-inout
16185     0/imm32/no-output
16186     0x11/imm32/alloc-id:fake
16187     _Primitive-break-if-addr<=-named/imm32/next
16188 _Primitive-break-if-addr<=-named:  # (payload primitive)
16189     0x11/imm32/alloc-id:fake:payload
16190     0x11/imm32/alloc-id:fake
16191     _string-break-if-addr<=/imm32/name
16192     0x11/imm32/alloc-id:fake
16193     Single-lit-var/imm32/inouts
16194     0/imm32/no-outputs
16195     0/imm32/no-outputs
16196     0x11/imm32/alloc-id:fake
16197     _string_0f_86_jump_label/imm32/subx-name
16198     0/imm32/no-rm32
16199     0/imm32/no-r32
16200     0/imm32/no-imm32
16201     1/imm32/disp32-is-first-inout
16202     0/imm32/no-output
16203     0x11/imm32/alloc-id:fake
16204     _Primitive-break-if-addr>-named/imm32/next
16205 _Primitive-break-if-addr>-named:  # (payload primitive)
16206     0x11/imm32/alloc-id:fake:payload
16207     0x11/imm32/alloc-id:fake
16208     _string-break-if-addr>/imm32/name
16209     0x11/imm32/alloc-id:fake
16210     Single-lit-var/imm32/inouts
16211     0/imm32/no-outputs
16212     0/imm32/no-outputs
16213     0x11/imm32/alloc-id:fake
16214     _string_0f_87_jump_label/imm32/subx-name
16215     0/imm32/no-rm32
16216     0/imm32/no-r32
16217     0/imm32/no-imm32
16218     1/imm32/disp32-is-first-inout
16219     0/imm32/no-output
16220     0x11/imm32/alloc-id:fake
16221     _Primitive-break-if-<-named/imm32/next
16222 _Primitive-break-if-<-named:  # (payload primitive)
16223     0x11/imm32/alloc-id:fake:payload
16224     0x11/imm32/alloc-id:fake
16225     _string-break-if-</imm32/name
16226     0x11/imm32/alloc-id:fake
16227     Single-lit-var/imm32/inouts
16228     0/imm32/no-outputs
16229     0/imm32/no-outputs
16230     0x11/imm32/alloc-id:fake
16231     _string_0f_8c_jump_label/imm32/subx-name
16232     0/imm32/no-rm32
16233     0/imm32/no-r32
16234     0/imm32/no-imm32
16235     1/imm32/disp32-is-first-inout
16236     0/imm32/no-output
16237     0x11/imm32/alloc-id:fake
16238     _Primitive-break-if->=-named/imm32/next
16239 _Primitive-break-if->=-named:  # (payload primitive)
16240     0x11/imm32/alloc-id:fake:payload
16241     0x11/imm32/alloc-id:fake
16242     _string-break-if->=/imm32/name
16243     0x11/imm32/alloc-id:fake
16244     Single-lit-var/imm32/inouts
16245     0/imm32/no-outputs
16246     0/imm32/no-outputs
16247     0x11/imm32/alloc-id:fake
16248     _string_0f_8d_jump_label/imm32/subx-name
16249     0/imm32/no-rm32
16250     0/imm32/no-r32
16251     0/imm32/no-imm32
16252     1/imm32/disp32-is-first-inout
16253     0/imm32/no-output
16254     0x11/imm32/alloc-id:fake
16255     _Primitive-break-if-<=-named/imm32/next
16256 _Primitive-break-if-<=-named:  # (payload primitive)
16257     0x11/imm32/alloc-id:fake:payload
16258     0x11/imm32/alloc-id:fake
16259     _string-break-if-<=/imm32/name
16260     0x11/imm32/alloc-id:fake
16261     Single-lit-var/imm32/inouts
16262     0/imm32/no-outputs
16263     0/imm32/no-outputs
16264     0x11/imm32/alloc-id:fake
16265     _string_0f_8e_jump_label/imm32/subx-name
16266     0/imm32/no-rm32
16267     0/imm32/no-r32
16268     0/imm32/no-imm32
16269     1/imm32/disp32-is-first-inout
16270     0/imm32/no-output
16271     0x11/imm32/alloc-id:fake
16272     _Primitive-break-if->-named/imm32/next
16273 _Primitive-break-if->-named:  # (payload primitive)
16274     0x11/imm32/alloc-id:fake:payload
16275     0x11/imm32/alloc-id:fake
16276     _string-break-if->/imm32/name
16277     0x11/imm32/alloc-id:fake
16278     Single-lit-var/imm32/inouts
16279     0/imm32/no-outputs
16280     0/imm32/no-outputs
16281     0x11/imm32/alloc-id:fake
16282     _string_0f_8f_jump_label/imm32/subx-name
16283     0/imm32/no-rm32
16284     0/imm32/no-r32
16285     0/imm32/no-imm32
16286     1/imm32/disp32-is-first-inout
16287     0/imm32/no-output
16288     0x11/imm32/alloc-id:fake
16289     _Primitive-break-named/imm32/next
16290 _Primitive-break-named:  # (payload primitive)
16291     0x11/imm32/alloc-id:fake:payload
16292     0x11/imm32/alloc-id:fake
16293     _string-break/imm32/name
16294     0x11/imm32/alloc-id:fake
16295     Single-lit-var/imm32/inouts
16296     0/imm32/no-outputs
16297     0/imm32/no-outputs
16298     0x11/imm32/alloc-id:fake
16299     _string_e9_jump_label/imm32/subx-name
16300     0/imm32/no-rm32
16301     0/imm32/no-r32
16302     0/imm32/no-imm32
16303     1/imm32/disp32-is-first-inout
16304     0/imm32/no-output
16305     0x11/imm32/alloc-id:fake
16306     _Primitive-loop-if-addr<-named/imm32/next
16307 _Primitive-loop-if-addr<-named:  # (payload primitive)
16308     0x11/imm32/alloc-id:fake:payload
16309     0x11/imm32/alloc-id:fake
16310     _string-loop-if-addr</imm32/name
16311     0x11/imm32/alloc-id:fake
16312     Single-lit-var/imm32/inouts
16313     0/imm32/no-outputs
16314     0/imm32/no-outputs
16315     0x11/imm32/alloc-id:fake
16316     _string_0f_82_jump_label/imm32/subx-name
16317     0/imm32/no-rm32
16318     0/imm32/no-r32
16319     0/imm32/no-imm32
16320     1/imm32/disp32-is-first-inout
16321     0/imm32/no-output
16322     0x11/imm32/alloc-id:fake
16323     _Primitive-loop-if-addr>=-named/imm32/next
16324 _Primitive-loop-if-addr>=-named:  # (payload primitive)
16325     0x11/imm32/alloc-id:fake:payload
16326     0x11/imm32/alloc-id:fake
16327     _string-loop-if-addr>=/imm32/name
16328     0x11/imm32/alloc-id:fake
16329     Single-lit-var/imm32/inouts
16330     0/imm32/no-outputs
16331     0/imm32/no-outputs
16332     0x11/imm32/alloc-id:fake
16333     _string_0f_83_jump_label/imm32/subx-name
16334     0/imm32/no-rm32
16335     0/imm32/no-r32
16336     0/imm32/no-imm32
16337     1/imm32/disp32-is-first-inout
16338     0/imm32/no-output
16339     0x11/imm32/alloc-id:fake
16340     _Primitive-loop-if-=-named/imm32/next
16341 _Primitive-loop-if-=-named:  # (payload primitive)
16342     0x11/imm32/alloc-id:fake:payload
16343     0x11/imm32/alloc-id:fake
16344     _string-loop-if-=/imm32/name
16345     0x11/imm32/alloc-id:fake
16346     Single-lit-var/imm32/inouts
16347     0/imm32/no-outputs
16348     0/imm32/no-outputs
16349     0x11/imm32/alloc-id:fake
16350     _string_0f_84_jump_label/imm32/subx-name
16351     0/imm32/no-rm32
16352     0/imm32/no-r32
16353     0/imm32/no-imm32
16354     1/imm32/disp32-is-first-inout
16355     0/imm32/no-output
16356     0x11/imm32/alloc-id:fake
16357     _Primitive-loop-if-!=-named/imm32/next
16358 _Primitive-loop-if-!=-named:  # (payload primitive)
16359     0x11/imm32/alloc-id:fake:payload
16360     0x11/imm32/alloc-id:fake
16361     _string-loop-if-!=/imm32/name
16362     0x11/imm32/alloc-id:fake
16363     Single-lit-var/imm32/inouts
16364     0/imm32/no-outputs
16365     0/imm32/no-outputs
16366     0x11/imm32/alloc-id:fake
16367     _string_0f_85_jump_label/imm32/subx-name
16368     0/imm32/no-rm32
16369     0/imm32/no-r32
16370     0/imm32/no-imm32
16371     1/imm32/disp32-is-first-inout
16372     0/imm32/no-output
16373     0x11/imm32/alloc-id:fake
16374     _Primitive-loop-if-addr<=-named/imm32/next
16375 _Primitive-loop-if-addr<=-named:  # (payload primitive)
16376     0x11/imm32/alloc-id:fake:payload
16377     0x11/imm32/alloc-id:fake
16378     _string-loop-if-addr<=/imm32/name
16379     0x11/imm32/alloc-id:fake
16380     Single-lit-var/imm32/inouts
16381     0/imm32/no-outputs
16382     0/imm32/no-outputs
16383     0x11/imm32/alloc-id:fake
16384     _string_0f_86_jump_label/imm32/subx-name
16385     0/imm32/no-rm32
16386     0/imm32/no-r32
16387     0/imm32/no-imm32
16388     1/imm32/disp32-is-first-inout
16389     0/imm32/no-output
16390     0x11/imm32/alloc-id:fake
16391     _Primitive-loop-if-addr>-named/imm32/next
16392 _Primitive-loop-if-addr>-named:  # (payload primitive)
16393     0x11/imm32/alloc-id:fake:payload
16394     0x11/imm32/alloc-id:fake
16395     _string-loop-if-addr>/imm32/name
16396     0x11/imm32/alloc-id:fake
16397     Single-lit-var/imm32/inouts
16398     0/imm32/no-outputs
16399     0/imm32/no-outputs
16400     0x11/imm32/alloc-id:fake
16401     _string_0f_87_jump_label/imm32/subx-name
16402     0/imm32/no-rm32
16403     0/imm32/no-r32
16404     0/imm32/no-imm32
16405     1/imm32/disp32-is-first-inout
16406     0/imm32/no-output
16407     0x11/imm32/alloc-id:fake
16408     _Primitive-loop-if-<-named/imm32/next
16409 _Primitive-loop-if-<-named:  # (payload primitive)
16410     0x11/imm32/alloc-id:fake:payload
16411     0x11/imm32/alloc-id:fake
16412     _string-loop-if-</imm32/name
16413     0x11/imm32/alloc-id:fake
16414     Single-lit-var/imm32/inouts
16415     0/imm32/no-outputs
16416     0/imm32/no-outputs
16417     0x11/imm32/alloc-id:fake
16418     _string_0f_8c_jump_label/imm32/subx-name
16419     0/imm32/no-rm32
16420     0/imm32/no-r32
16421     0/imm32/no-imm32
16422     1/imm32/disp32-is-first-inout
16423     0/imm32/no-output
16424     0x11/imm32/alloc-id:fake
16425     _Primitive-loop-if->=-named/imm32/next
16426 _Primitive-loop-if->=-named:  # (payload primitive)
16427     0x11/imm32/alloc-id:fake:payload
16428     0x11/imm32/alloc-id:fake
16429     _string-loop-if->=/imm32/name
16430     0x11/imm32/alloc-id:fake
16431     Single-lit-var/imm32/inouts
16432     0/imm32/no-outputs
16433     0/imm32/no-outputs
16434     0x11/imm32/alloc-id:fake
16435     _string_0f_8d_jump_label/imm32/subx-name
16436     0/imm32/no-rm32
16437     0/imm32/no-r32
16438     0/imm32/no-imm32
16439     1/imm32/disp32-is-first-inout
16440     0/imm32/no-output
16441     0x11/imm32/alloc-id:fake
16442     _Primitive-loop-if-<=-named/imm32/next
16443 _Primitive-loop-if-<=-named:  # (payload primitive)
16444     0x11/imm32/alloc-id:fake:payload
16445     0x11/imm32/alloc-id:fake
16446     _string-loop-if-<=/imm32/name
16447     0x11/imm32/alloc-id:fake
16448     Single-lit-var/imm32/inouts
16449     0/imm32/no-outputs
16450     0/imm32/no-outputs
16451     0x11/imm32/alloc-id:fake
16452     _string_0f_8e_jump_label/imm32/subx-name
16453     0/imm32/no-rm32
16454     0/imm32/no-r32
16455     0/imm32/no-imm32
16456     1/imm32/disp32-is-first-inout
16457     0/imm32/no-output
16458     0x11/imm32/alloc-id:fake
16459     _Primitive-loop-if->-named/imm32/next
16460 _Primitive-loop-if->-named:  # (payload primitive)
16461     0x11/imm32/alloc-id:fake:payload
16462     0x11/imm32/alloc-id:fake
16463     _string-loop-if->/imm32/name
16464     0x11/imm32/alloc-id:fake
16465     Single-lit-var/imm32/inouts
16466     0/imm32/no-outputs
16467     0/imm32/no-outputs
16468     0x11/imm32/alloc-id:fake
16469     _string_0f_8f_jump_label/imm32/subx-name
16470     0/imm32/no-rm32
16471     0/imm32/no-r32
16472     0/imm32/no-imm32
16473     1/imm32/disp32-is-first-inout
16474     0/imm32/no-output
16475     0x11/imm32/alloc-id:fake
16476     _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
16477 _Primitive-loop-named:  # (payload primitive)
16478     0x11/imm32/alloc-id:fake:payload
16479     0x11/imm32/alloc-id:fake
16480     _string-loop/imm32/name
16481     0x11/imm32/alloc-id:fake
16482     Single-lit-var/imm32/inouts
16483     0/imm32/no-outputs
16484     0/imm32/no-outputs
16485     0x11/imm32/alloc-id:fake
16486     _string_e9_jump_label/imm32/subx-name
16487     0/imm32/no-rm32
16488     0/imm32/no-r32
16489     0/imm32/no-imm32
16490     1/imm32/disp32-is-first-inout
16491     0/imm32/no-output
16492     0/imm32/next
16493     0/imm32/next
16494 
16495 # string literals for Mu instructions
16496 _string-add:  # (payload array byte)
16497     0x11/imm32/alloc-id:fake:payload
16498     # "add"
16499     0x3/imm32/size
16500     0x61/a 0x64/d 0x64/d
16501 _string-address:  # (payload array byte)
16502     0x11/imm32/alloc-id:fake:payload
16503     # "address"
16504     0x7/imm32/size
16505     0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
16506 _string-add-to:  # (payload array byte)
16507     0x11/imm32/alloc-id:fake:payload
16508     # "add-to"
16509     0x6/imm32/size
16510     0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
16511 _string-and:  # (payload array byte)
16512     0x11/imm32/alloc-id:fake:payload
16513     # "and"
16514     0x3/imm32/size
16515     0x61/a 0x6e/n 0x64/d
16516 _string-and-with:  # (payload array byte)
16517     0x11/imm32/alloc-id:fake:payload
16518     # "and-with"
16519     0x8/imm32/size
16520     0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16521 _string-break:  # (payload array byte)
16522     0x11/imm32/alloc-id:fake:payload
16523     # "break"
16524     0x5/imm32/size
16525     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
16526 _string-break-if-<:  # (payload array byte)
16527     0x11/imm32/alloc-id:fake:payload
16528     # "break-if-<"
16529     0xa/imm32/size
16530     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
16531 _string-break-if-<=:  # (payload array byte)
16532     0x11/imm32/alloc-id:fake:payload
16533     # "break-if-<="
16534     0xb/imm32/size
16535     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
16536 _string-break-if-=:  # (payload array byte)
16537     0x11/imm32/alloc-id:fake:payload
16538     # "break-if-="
16539     0xa/imm32/size
16540     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
16541 _string-break-if->:  # (payload array byte)
16542     0x11/imm32/alloc-id:fake:payload
16543     # "break-if->"
16544     0xa/imm32/size
16545     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
16546 _string-break-if->=:  # (payload array byte)
16547     0x11/imm32/alloc-id:fake:payload
16548     # "break-if->="
16549     0xb/imm32/size
16550     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
16551 _string-break-if-!=:  # (payload array byte)
16552     0x11/imm32/alloc-id:fake:payload
16553     # "break-if-!="
16554     0xb/imm32/size
16555     0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
16556 _string-break-if-addr<:  # (payload array byte)
16557     0x11/imm32/alloc-id:fake:payload
16558     # "break-if-addr<"
16559     0xe/imm32/size
16560     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/<
16561 _string-break-if-addr<=:  # (payload array byte)
16562     0x11/imm32/alloc-id:fake:payload
16563     # "break-if-addr<="
16564     0xf/imm32/size
16565     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/=
16566 _string-break-if-addr>:  # (payload array byte)
16567     0x11/imm32/alloc-id:fake:payload
16568     # "break-if-addr>"
16569     0xe/imm32/size
16570     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/>
16571 _string-break-if-addr>=:  # (payload array byte)
16572     0x11/imm32/alloc-id:fake:payload
16573     # "break-if-addr>="
16574     0xf/imm32/size
16575     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/=
16576 _string-compare:  # (payload array byte)
16577     0x11/imm32/alloc-id:fake:payload
16578     # "compare"
16579     0x7/imm32/size
16580     0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
16581 _string-copy:  # (payload array byte)
16582     0x11/imm32/alloc-id:fake:payload
16583     # "copy"
16584     0x4/imm32/size
16585     0x63/c 0x6f/o 0x70/p 0x79/y
16586 _string-copy-to:  # (payload array byte)
16587     0x11/imm32/alloc-id:fake:payload
16588     # "copy-to"
16589     0x7/imm32/size
16590     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
16591 _string-copy-byte:
16592     0x11/imm32/alloc-id:fake:payload
16593     # "copy-byte"
16594     0x9/imm32/size
16595     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
16596 _string-copy-byte-to:
16597     0x11/imm32/alloc-id:fake:payload
16598     # "copy-byte-to"
16599     0xc/imm32/size
16600     0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
16601 _string-decrement:  # (payload array byte)
16602     0x11/imm32/alloc-id:fake:payload
16603     # "decrement"
16604     0x9/imm32/size
16605     0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
16606 _string-increment:  # (payload array byte)
16607     0x11/imm32/alloc-id:fake:payload
16608     # "increment"
16609     0x9/imm32/size
16610     0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
16611 _string-loop:  # (payload array byte)
16612     0x11/imm32/alloc-id:fake:payload
16613     # "loop"
16614     0x4/imm32/size
16615     0x6c/l 0x6f/o 0x6f/o 0x70/p
16616 _string-loop-if-<:  # (payload array byte)
16617     0x11/imm32/alloc-id:fake:payload
16618     # "loop-if-<"
16619     0x9/imm32/size
16620     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
16621 _string-loop-if-<=:  # (payload array byte)
16622     0x11/imm32/alloc-id:fake:payload
16623     # "loop-if-<="
16624     0xa/imm32/size
16625     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
16626 _string-loop-if-=:  # (payload array byte)
16627     0x11/imm32/alloc-id:fake:payload
16628     # "loop-if-="
16629     0x9/imm32/size
16630     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
16631 _string-loop-if->:  # (payload array byte)
16632     0x11/imm32/alloc-id:fake:payload
16633     # "loop-if->"
16634     0x9/imm32/size
16635     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
16636 _string-loop-if->=:  # (payload array byte)
16637     0x11/imm32/alloc-id:fake:payload
16638     # "loop-if->="
16639     0xa/imm32/size
16640     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
16641 _string-loop-if-!=:  # (payload array byte)
16642     0x11/imm32/alloc-id:fake:payload
16643     # "loop-if-!="
16644     0xa/imm32/size
16645     0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
16646 _string-loop-if-addr<:  # (payload array byte)
16647     0x11/imm32/alloc-id:fake:payload
16648     # "loop-if-addr<"
16649     0xd/imm32/size
16650     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/<
16651 _string-loop-if-addr<=:  # (payload array byte)
16652     0x11/imm32/alloc-id:fake:payload
16653     # "loop-if-addr<="
16654     0xe/imm32/size
16655     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/=
16656 _string-loop-if-addr>:  # (payload array byte)
16657     0x11/imm32/alloc-id:fake:payload
16658     # "loop-if-addr>"
16659     0xd/imm32/size
16660     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/>
16661 _string-loop-if-addr>=:  # (payload array byte)
16662     0x11/imm32/alloc-id:fake:payload
16663     # "loop-if-addr>="
16664     0xe/imm32/size
16665     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/=
16666 _string-multiply:  # (payload array byte)
16667     0x11/imm32/alloc-id:fake:payload
16668     # "multiply"
16669     0x8/imm32/size
16670     0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
16671 _string-or:  # (payload array byte)
16672     0x11/imm32/alloc-id:fake:payload
16673     # "or"
16674     0x2/imm32/size
16675     0x6f/o 0x72/r
16676 _string-or-with:  # (payload array byte)
16677     0x11/imm32/alloc-id:fake:payload
16678     # "or-with"
16679     0x7/imm32/size
16680     0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16681 _string-subtract:  # (payload array byte)
16682     0x11/imm32/alloc-id:fake:payload
16683     # "subtract"
16684     0x8/imm32/size
16685     0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
16686 _string-subtract-from:  # (payload array byte)
16687     0x11/imm32/alloc-id:fake:payload
16688     # "subtract-from"
16689     0xd/imm32/size
16690     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
16691 _string-xor:  # (payload array byte)
16692     0x11/imm32/alloc-id:fake:payload
16693     # "xor"
16694     0x3/imm32/size
16695     0x78/x 0x6f/o 0x72/r
16696 _string-xor-with:  # (payload array byte)
16697     0x11/imm32/alloc-id:fake:payload
16698     # "xor-with"
16699     0x8/imm32/size
16700     0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16701 
16702 # string literals for SubX instructions
16703 _string_01_add_to:  # (payload array byte)
16704     0x11/imm32/alloc-id:fake:payload
16705     # "01/add-to"
16706     0x9/imm32/size
16707     0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
16708 _string_03_add:  # (payload array byte)
16709     0x11/imm32/alloc-id:fake:payload
16710     # "03/add"
16711     0x6/imm32/size
16712     0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
16713 _string_05_add_to_eax:  # (payload array byte)
16714     0x11/imm32/alloc-id:fake:payload
16715     # "05/add-to-eax"
16716     0xd/imm32/size
16717     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
16718 _string_09_or_with:  # (payload array byte)
16719     0x11/imm32/alloc-id:fake:payload
16720     # "09/or-with"
16721     0xa/imm32/size
16722     0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16723 _string_0b_or:  # (payload array byte)
16724     0x11/imm32/alloc-id:fake:payload
16725     # "0b/or"
16726     0x5/imm32/size
16727     0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
16728 _string_0d_or_with_eax:  # (payload array byte)
16729     0x11/imm32/alloc-id:fake:payload
16730     # "0d/or-with-eax"
16731     0xe/imm32/size
16732     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
16733 _string_0f_82_jump_label:  # (payload array byte)
16734     0x11/imm32/alloc-id:fake:payload
16735     # "0f 82/jump-if-addr<"
16736     0x13/imm32/size
16737     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/<
16738 _string_0f_82_jump_break:  # (payload array byte)
16739     0x11/imm32/alloc-id:fake:payload
16740     # "0f 82/jump-if-addr< break/disp32"
16741     0x20/imm32/size
16742     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
16743 _string_0f_82_jump_loop:  # (payload array byte)
16744     0x11/imm32/alloc-id:fake:payload
16745     # "0f 82/jump-if-addr< loop/disp32"
16746     0x1f/imm32/size
16747     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
16748 _string_0f_83_jump_label:  # (payload array byte)
16749     0x11/imm32/alloc-id:fake:payload
16750     # "0f 83/jump-if-addr>="
16751     0x14/imm32/size
16752     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/=
16753 _string_0f_83_jump_break:  # (payload array byte)
16754     0x11/imm32/alloc-id:fake:payload
16755     # "0f 83/jump-if-addr>= break/disp32"
16756     0x21/imm32/size
16757     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
16758 _string_0f_83_jump_loop:  # (payload array byte)
16759     0x11/imm32/alloc-id:fake:payload
16760     # "0f 83/jump-if-addr>= loop/disp32"
16761     0x20/imm32/size
16762     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
16763 _string_0f_84_jump_label:  # (payload array byte)
16764     0x11/imm32/alloc-id:fake:payload
16765     # "0f 84/jump-if-="
16766     0xf/imm32/size
16767     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/=
16768 _string_0f_84_jump_break:  # (payload array byte)
16769     0x11/imm32/alloc-id:fake:payload
16770     # "0f 84/jump-if-= break/disp32"
16771     0x1c/imm32/size
16772     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
16773 _string_0f_84_jump_loop:  # (payload array byte)
16774     0x11/imm32/alloc-id:fake:payload
16775     # "0f 84/jump-if-= loop/disp32"
16776     0x1b/imm32/size
16777     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
16778 _string_0f_85_jump_label:  # (payload array byte)
16779     0x11/imm32/alloc-id:fake:payload
16780     # "0f 85/jump-if-!="
16781     0x10/imm32/size
16782     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/=
16783 _string_0f_85_jump_break:  # (payload array byte)
16784     0x11/imm32/alloc-id:fake:payload
16785     # "0f 85/jump-if-!= break/disp32"
16786     0x1d/imm32/size
16787     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
16788 _string_0f_85_jump_loop:  # (payload array byte)
16789     0x11/imm32/alloc-id:fake:payload
16790     # "0f 85/jump-if-!= loop/disp32"
16791     0x1c/imm32/size
16792     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
16793 _string_0f_86_jump_label:  # (payload array byte)
16794     0x11/imm32/alloc-id:fake:payload
16795     # "0f 86/jump-if-addr<="
16796     0x14/imm32/size
16797     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/=
16798 _string_0f_86_jump_break:  # (payload array byte)
16799     0x11/imm32/alloc-id:fake:payload
16800     # "0f 86/jump-if-addr<= break/disp32"
16801     0x21/imm32/size
16802     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
16803 _string_0f_86_jump_loop:  # (payload array byte)
16804     0x11/imm32/alloc-id:fake:payload
16805     # "0f 86/jump-if-addr<= loop/disp32"
16806     0x20/imm32/size
16807     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
16808 _string_0f_87_jump_label:  # (payload array byte)
16809     0x11/imm32/alloc-id:fake:payload
16810     # "0f 87/jump-if-addr>"
16811     0x13/imm32/size
16812     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/>
16813 _string_0f_87_jump_break:  # (payload array byte)
16814     0x11/imm32/alloc-id:fake:payload
16815     # "0f 87/jump-if-addr> break/disp32"
16816     0x20/imm32/size
16817     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
16818 _string_0f_87_jump_loop:  # (payload array byte)
16819     0x11/imm32/alloc-id:fake:payload
16820     # "0f 87/jump-if-addr> loop/disp32"
16821     0x1f/imm32/size
16822     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
16823 _string_0f_8c_jump_label:  # (payload array byte)
16824     0x11/imm32/alloc-id:fake:payload
16825     # "0f 8c/jump-if-<"
16826     0xf/imm32/size
16827     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/<
16828 _string_0f_8c_jump_break:  # (payload array byte)
16829     0x11/imm32/alloc-id:fake:payload
16830     # "0f 8c/jump-if-< break/disp32"
16831     0x1c/imm32/size
16832     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
16833 _string_0f_8c_jump_loop:  # (payload array byte)
16834     0x11/imm32/alloc-id:fake:payload
16835     # "0f 8c/jump-if-< loop/disp32"
16836     0x1b/imm32/size
16837     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
16838 _string_0f_8d_jump_label:  # (payload array byte)
16839     0x11/imm32/alloc-id:fake:payload
16840     # "0f 8d/jump-if->="
16841     0x10/imm32/size
16842     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/=
16843 _string_0f_8d_jump_break:  # (payload array byte)
16844     0x11/imm32/alloc-id:fake:payload
16845     # "0f 8d/jump-if->= break/disp32"
16846     0x1d/imm32/size
16847     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
16848 _string_0f_8d_jump_loop:  # (payload array byte)
16849     0x11/imm32/alloc-id:fake:payload
16850     # "0f 8d/jump-if->= loop/disp32"
16851     0x1c/imm32/size
16852     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
16853 _string_0f_8e_jump_label:  # (payload array byte)
16854     0x11/imm32/alloc-id:fake:payload
16855     # "0f 8e/jump-if-<="
16856     0x10/imm32/size
16857     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/=
16858 _string_0f_8e_jump_break:  # (payload array byte)
16859     0x11/imm32/alloc-id:fake:payload
16860     # "0f 8e/jump-if-<= break/disp32"
16861     0x1d/imm32/size
16862     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
16863 _string_0f_8e_jump_loop:  # (payload array byte)
16864     0x11/imm32/alloc-id:fake:payload
16865     # "0f 8e/jump-if-<= loop/disp32"
16866     0x1c/imm32/size
16867     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
16868 _string_0f_8f_jump_label:  # (payload array byte)
16869     0x11/imm32/alloc-id:fake:payload
16870     # "0f 8f/jump-if->"
16871     0xf/imm32/size
16872     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/>
16873 _string_0f_8f_jump_break:  # (payload array byte)
16874     0x11/imm32/alloc-id:fake:payload
16875     # "0f 8f/jump-if-> break/disp32"
16876     0x1c/imm32/size
16877     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
16878 _string_0f_8f_jump_loop:  # (payload array byte)
16879     0x11/imm32/alloc-id:fake:payload
16880     # "0f 8f/jump-if-> loop/disp32"
16881     0x1b/imm32/size
16882     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
16883 _string_0f_af_multiply:  # (payload array byte)
16884     0x11/imm32/alloc-id:fake:payload
16885     # "0f af/multiply"
16886     0xe/imm32/size
16887     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
16888 _string_21_and_with:  # (payload array byte)
16889     0x11/imm32/alloc-id:fake:payload
16890     # "21/and-with"
16891     0xb/imm32/size
16892     0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16893 _string_23_and:  # (payload array byte)
16894     0x11/imm32/alloc-id:fake:payload
16895     # "23/and"
16896     0x6/imm32/size
16897     0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
16898 _string_25_and_with_eax:  # (payload array byte)
16899     0x11/imm32/alloc-id:fake:payload
16900     # "25/and-with-eax"
16901     0xf/imm32/size
16902     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
16903 _string_29_subtract_from:  # (payload array byte)
16904     0x11/imm32/alloc-id:fake:payload
16905     # "29/subtract-from"
16906     0x10/imm32/size
16907     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
16908 _string_2b_subtract:  # (payload array byte)
16909     0x11/imm32/alloc-id:fake:payload
16910     # "2b/subtract"
16911     0xb/imm32/size
16912     0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
16913 _string_2d_subtract_from_eax:  # (payload array byte)
16914     0x11/imm32/alloc-id:fake:payload
16915     # "2d/subtract-from-eax"
16916     0x14/imm32/size
16917     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
16918 _string_31_xor_with:  # (payload array byte)
16919     0x11/imm32/alloc-id:fake:payload
16920     # "31/xor-with"
16921     0xb/imm32/size
16922     0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
16923 _string_33_xor:  # (payload array byte)
16924     0x11/imm32/alloc-id:fake:payload
16925     # "33/xor"
16926     0x6/imm32/size
16927     0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
16928 _string_35_xor_with_eax:  # (payload array byte)
16929     0x11/imm32/alloc-id:fake:payload
16930     # "35/xor-with-eax"
16931     0xf/imm32/size
16932     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
16933 _string_39_compare->:  # (payload array byte)
16934     0x11/imm32/alloc-id:fake:payload
16935     # "39/compare->"
16936     0xc/imm32/size
16937     0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
16938 _string_3b_compare<-:  # (payload array byte)
16939     0x11/imm32/alloc-id:fake:payload
16940     # "3b/compare<-"
16941     0xc/imm32/size
16942     0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
16943 _string_3d_compare_eax_with:  # (payload array byte)
16944     0x11/imm32/alloc-id:fake:payload
16945     # "3d/compare-eax-with"
16946     0x13/imm32/size
16947     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
16948 _string_40_increment_eax:  # (payload array byte)
16949     0x11/imm32/alloc-id:fake:payload
16950     # "40/increment-eax"
16951     0x10/imm32/size
16952     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
16953 _string_41_increment_ecx:  # (payload array byte)
16954     0x11/imm32/alloc-id:fake:payload
16955     # "41/increment-ecx"
16956     0x10/imm32/size
16957     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
16958 _string_42_increment_edx:  # (payload array byte)
16959     0x11/imm32/alloc-id:fake:payload
16960     # "42/increment-edx"
16961     0x10/imm32/size
16962     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
16963 _string_43_increment_ebx:  # (payload array byte)
16964     0x11/imm32/alloc-id:fake:payload
16965     # "43/increment-ebx"
16966     0x10/imm32/size
16967     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
16968 _string_46_increment_esi:  # (payload array byte)
16969     0x11/imm32/alloc-id:fake:payload
16970     # "46/increment-esi"
16971     0x10/imm32/size
16972     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
16973 _string_47_increment_edi:  # (payload array byte)
16974     0x11/imm32/alloc-id:fake:payload
16975     # "47/increment-edi"
16976     0x10/imm32/size
16977     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
16978 _string_48_decrement_eax:  # (payload array byte)
16979     0x11/imm32/alloc-id:fake:payload
16980     # "48/decrement-eax"
16981     0x10/imm32/size
16982     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
16983 _string_49_decrement_ecx:  # (payload array byte)
16984     0x11/imm32/alloc-id:fake:payload
16985     # "49/decrement-ecx"
16986     0x10/imm32/size
16987     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
16988 _string_4a_decrement_edx:  # (payload array byte)
16989     0x11/imm32/alloc-id:fake:payload
16990     # "4a/decrement-edx"
16991     0x10/imm32/size
16992     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
16993 _string_4b_decrement_ebx:  # (payload array byte)
16994     0x11/imm32/alloc-id:fake:payload
16995     # "4b/decrement-ebx"
16996     0x10/imm32/size
16997     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
16998 _string_4e_decrement_esi:  # (payload array byte)
16999     0x11/imm32/alloc-id:fake:payload
17000     # "4e/decrement-esi"
17001     0x10/imm32/size
17002     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
17003 _string_4f_decrement_edi:  # (payload array byte)
17004     0x11/imm32/alloc-id:fake:payload
17005     # "4f/decrement-edi"
17006     0x10/imm32/size
17007     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
17008 _string_81_subop_add:  # (payload array byte)
17009     0x11/imm32/alloc-id:fake:payload
17010     # "81 0/subop/add"
17011     0xe/imm32/size
17012     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
17013 _string_81_subop_or:  # (payload array byte)
17014     0x11/imm32/alloc-id:fake:payload
17015     # "81 1/subop/or"
17016     0xd/imm32/size
17017     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
17018 _string_81_subop_and:  # (payload array byte)
17019     0x11/imm32/alloc-id:fake:payload
17020     # "81 4/subop/and"
17021     0xe/imm32/size
17022     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
17023 _string_81_subop_subtract:  # (payload array byte)
17024     0x11/imm32/alloc-id:fake:payload
17025     # "81 5/subop/subtract"
17026     0x13/imm32/size
17027     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
17028 _string_81_subop_xor:  # (payload array byte)
17029     0x11/imm32/alloc-id:fake:payload
17030     # "81 6/subop/xor"
17031     0xe/imm32/size
17032     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
17033 _string_81_subop_compare:  # (payload array byte)
17034     0x11/imm32/alloc-id:fake:payload
17035     # "81 7/subop/compare"
17036     0x12/imm32/size
17037     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
17038 _string_89_<-:  # (payload array byte)
17039     0x11/imm32/alloc-id:fake:payload
17040     # "89/<-"
17041     0x5/imm32/size
17042     0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
17043 _string_8b_->:  # (payload array byte)
17044     0x11/imm32/alloc-id:fake:payload
17045     # "8b/->"
17046     0x5/imm32/size
17047     0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
17048 _string_8a_copy_byte:
17049     0x11/imm32/alloc-id:fake:payload
17050     # "8a/byte->"
17051     0x9/imm32/size
17052     0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
17053 _string_88_copy_byte:
17054     0x11/imm32/alloc-id:fake:payload
17055     # "88/byte<-"
17056     0x9/imm32/size
17057     0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
17058 _string_8d_copy_address:  # (payload array byte)
17059     0x11/imm32/alloc-id:fake:payload
17060     # "8d/copy-address"
17061     0xf/imm32/size
17062     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
17063 _string_b8_copy_to_eax:  # (payload array byte)
17064     0x11/imm32/alloc-id:fake:payload
17065     # "b8/copy-to-eax"
17066     0xe/imm32/size
17067     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
17068 _string_b9_copy_to_ecx:  # (payload array byte)
17069     0x11/imm32/alloc-id:fake:payload
17070     # "b9/copy-to-ecx"
17071     0xe/imm32/size
17072     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
17073 _string_ba_copy_to_edx:  # (payload array byte)
17074     0x11/imm32/alloc-id:fake:payload
17075     # "ba/copy-to-edx"
17076     0xe/imm32/size
17077     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
17078 _string_bb_copy_to_ebx:  # (payload array byte)
17079     0x11/imm32/alloc-id:fake:payload
17080     # "bb/copy-to-ebx"
17081     0xe/imm32/size
17082     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
17083 _string_be_copy_to_esi:  # (payload array byte)
17084     0x11/imm32/alloc-id:fake:payload
17085     # "be/copy-to-esi"
17086     0xe/imm32/size
17087     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
17088 _string_bf_copy_to_edi:  # (payload array byte)
17089     0x11/imm32/alloc-id:fake:payload
17090     # "bf/copy-to-edi"
17091     0xe/imm32/size
17092     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
17093 _string_c7_subop_copy:  # (payload array byte)
17094     0x11/imm32/alloc-id:fake:payload
17095     # "c7 0/subop/copy"
17096     0xf/imm32/size
17097     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
17098 _string_e9_jump_label:  # (payload array byte)
17099     0x11/imm32/alloc-id:fake:payload
17100     # "e9/jump"
17101     0x7/imm32/size
17102     0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
17103 _string_e9_jump_break:  # (payload array byte)
17104     0x11/imm32/alloc-id:fake:payload
17105     # "e9/jump break/disp32"
17106     0x14/imm32/size
17107     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
17108 _string_e9_jump_loop:  # (payload array byte)
17109     0x11/imm32/alloc-id:fake:payload
17110     # "e9/jump loop/disp32"
17111     0x13/imm32/size
17112     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
17113 _string_ff_subop_increment:  # (payload array byte)
17114     0x11/imm32/alloc-id:fake:payload
17115     # "ff 0/subop/increment"
17116     0x14/imm32/size
17117     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
17118 _string_ff_subop_decrement:  # (payload array byte)
17119     0x11/imm32/alloc-id:fake:payload
17120     # "ff 1/subop/decrement"
17121     0x14/imm32/size
17122     0x66/f 0x66/f 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
17123 
17124 Single-int-var-in-mem:  # (payload list var)
17125     0x11/imm32/alloc-id:fake:payload
17126     0x11/imm32/alloc-id:fake
17127     Int-var-in-mem/imm32
17128     0/imm32/next
17129     0/imm32/next
17130 
17131 Int-var-in-mem:  # (payload var)
17132     0x11/imm32/alloc-id:fake:payload
17133     0/imm32/name
17134     0/imm32/name
17135     0x11/imm32/alloc-id:fake
17136     Type-int/imm32
17137     1/imm32/some-block-depth
17138     1/imm32/some-stack-offset
17139     0/imm32/no-register
17140     0/imm32/no-register
17141 
17142 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
17143 Single-byte-var-in-mem:  # (payload list var)
17144     0x11/imm32/alloc-id:fake:payload
17145     0x11/imm32/alloc-id:fake
17146     Byte-var-in-mem/imm32
17147     0/imm32/next
17148     0/imm32/next
17149 
17150 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
17151 Byte-var-in-mem:  # (payload var)
17152     0x11/imm32/alloc-id:fake:payload
17153     0/imm32/name
17154     0/imm32/name
17155     0x11/imm32/alloc-id:fake
17156     Type-byte/imm32
17157     1/imm32/some-block-depth
17158     1/imm32/some-stack-offset
17159     0/imm32/no-register
17160     0/imm32/no-register
17161 
17162 Two-args-int-stack-int-reg:  # (payload list var)
17163     0x11/imm32/alloc-id:fake:payload
17164     0x11/imm32/alloc-id:fake
17165     Int-var-in-mem/imm32
17166     0x11/imm32/alloc-id:fake
17167     Single-int-var-in-some-register/imm32/next
17168 
17169 Two-int-args-in-regs:  # (payload list var)
17170     0x11/imm32/alloc-id:fake:payload
17171     0x11/imm32/alloc-id:fake
17172     Int-var-in-some-register/imm32
17173     0x11/imm32/alloc-id:fake
17174     Single-int-var-in-some-register/imm32/next
17175 
17176 # Not really legal, but closest we can currently represent a dereference of an (addr byte)
17177 Two-args-byte-stack-byte-reg:  # (payload list var)
17178     0x11/imm32/alloc-id:fake:payload
17179     0x11/imm32/alloc-id:fake
17180     Byte-var-in-mem/imm32
17181     0x11/imm32/alloc-id:fake
17182     Single-byte-var-in-some-register/imm32/next
17183 
17184 Two-args-int-reg-int-stack:  # (payload list var)
17185     0x11/imm32/alloc-id:fake:payload
17186     0x11/imm32/alloc-id:fake
17187     Int-var-in-some-register/imm32
17188     0x11/imm32/alloc-id:fake
17189     Single-int-var-in-mem/imm32/next
17190 
17191 Two-args-int-eax-int-literal:  # (payload list var)
17192     0x11/imm32/alloc-id:fake:payload
17193     0x11/imm32/alloc-id:fake
17194     Int-var-in-eax/imm32
17195     0x11/imm32/alloc-id:fake
17196     Single-lit-var/imm32/next
17197 
17198 Int-var-and-literal:  # (payload list var)
17199     0x11/imm32/alloc-id:fake:payload
17200     0x11/imm32/alloc-id:fake
17201     Int-var-in-mem/imm32
17202     0x11/imm32/alloc-id:fake
17203     Single-lit-var/imm32/next
17204 
17205 Int-var-in-register-and-literal:  # (payload list var)
17206     0x11/imm32/alloc-id:fake:payload
17207     0x11/imm32/alloc-id:fake
17208     Int-var-in-some-register/imm32
17209     0x11/imm32/alloc-id:fake
17210     Single-lit-var/imm32/next
17211 
17212 Single-int-var-in-some-register:  # (payload list var)
17213     0x11/imm32/alloc-id:fake:payload
17214     0x11/imm32/alloc-id:fake
17215     Int-var-in-some-register/imm32
17216     0/imm32/next
17217     0/imm32/next
17218 
17219 Single-addr-var-in-some-register:  # (payload list var)
17220     0x11/imm32/alloc-id:fake:payload
17221     0x11/imm32/alloc-id:fake
17222     Addr-var-in-some-register/imm32
17223     0/imm32/next
17224     0/imm32/next
17225 
17226 Single-byte-var-in-some-register:  # (payload list var)
17227     0x11/imm32/alloc-id:fake:payload
17228     0x11/imm32/alloc-id:fake
17229     Byte-var-in-some-register/imm32
17230     0/imm32/next
17231     0/imm32/next
17232 
17233 Int-var-in-some-register:  # (payload var)
17234     0x11/imm32/alloc-id:fake:payload
17235     0/imm32/name
17236     0/imm32/name
17237     0x11/imm32/alloc-id:fake
17238     Type-int/imm32
17239     1/imm32/some-block-depth
17240     0/imm32/no-stack-offset
17241     0x11/imm32/alloc-id:fake
17242     Any-register/imm32
17243 
17244 Any-register:  # (payload array byte)
17245     0x11/imm32/alloc-id:fake:payload
17246     1/imm32/size
17247     # data
17248     2a/asterisk
17249 
17250 Addr-var-in-some-register:  # (payload var)
17251     0x11/imm32/alloc-id:fake:payload
17252     0/imm32/name
17253     0/imm32/name
17254     0x11/imm32/alloc-id:fake
17255     Type-addr/imm32
17256     1/imm32/some-block-depth
17257     0/imm32/no-stack-offset
17258     0x11/imm32/alloc-id:fake
17259     Any-register/imm32
17260 
17261 Byte-var-in-some-register:  # (payload var)
17262     0x11/imm32/alloc-id:fake:payload
17263     0/imm32/name
17264     0/imm32/name
17265     0x11/imm32/alloc-id:fake
17266     Type-byte/imm32
17267     1/imm32/some-block-depth
17268     0/imm32/no-stack-offset
17269     0x11/imm32/alloc-id:fake
17270     Any-register/imm32
17271 
17272 Single-int-var-in-eax:  # (payload list var)
17273     0x11/imm32/alloc-id:fake:payload
17274     0x11/imm32/alloc-id:fake
17275     Int-var-in-eax/imm32
17276     0/imm32/next
17277     0/imm32/next
17278 
17279 Int-var-in-eax:
17280     0x11/imm32/alloc-id:fake:payload
17281     0/imm32/name
17282     0/imm32/name
17283     0x11/imm32/alloc-id:fake
17284     Type-int/imm32
17285     1/imm32/some-block-depth
17286     0/imm32/no-stack-offset
17287     0x11/imm32/alloc-id:fake
17288     $Register-eax/imm32
17289 
17290 Single-int-var-in-ecx:  # (payload list var)
17291     0x11/imm32/alloc-id:fake:payload
17292     0x11/imm32/alloc-id:fake
17293     Int-var-in-ecx/imm32
17294     0/imm32/next
17295     0/imm32/next
17296 
17297 Int-var-in-ecx:
17298     0x11/imm32/alloc-id:fake:payload
17299     0/imm32/name
17300     0/imm32/name
17301     0x11/imm32/alloc-id:fake
17302     Type-int/imm32
17303     1/imm32/some-block-depth
17304     0/imm32/no-stack-offset
17305     0x11/imm32/alloc-id:fake
17306     $Register-ecx/imm32/register
17307 
17308 Single-int-var-in-edx:  # (payload list var)
17309     0x11/imm32/alloc-id:fake:payload
17310     0x11/imm32/alloc-id:fake
17311     Int-var-in-edx/imm32
17312     0/imm32/next
17313     0/imm32/next
17314 
17315 Int-var-in-edx:  # (payload list var)
17316     0x11/imm32/alloc-id:fake:payload
17317     0/imm32/name
17318     0/imm32/name
17319     0x11/imm32/alloc-id:fake
17320     Type-int/imm32
17321     1/imm32/some-block-depth
17322     0/imm32/no-stack-offset
17323     0x11/imm32/alloc-id:fake
17324     $Register-edx/imm32/register
17325 
17326 Single-int-var-in-ebx:  # (payload list var)
17327     0x11/imm32/alloc-id:fake:payload
17328     0x11/imm32/alloc-id:fake
17329     Int-var-in-ebx/imm32
17330     0/imm32/next
17331     0/imm32/next
17332 
17333 Int-var-in-ebx:  # (payload list var)
17334     0x11/imm32/alloc-id:fake:payload
17335     0/imm32/name
17336     0/imm32/name
17337     0x11/imm32/alloc-id:fake
17338     Type-int/imm32
17339     1/imm32/some-block-depth
17340     0/imm32/no-stack-offset
17341     0x11/imm32/alloc-id:fake
17342     $Register-ebx/imm32/register
17343 
17344 Single-int-var-in-esi:  # (payload list var)
17345     0x11/imm32/alloc-id:fake:payload
17346     0x11/imm32/alloc-id:fake
17347     Int-var-in-esi/imm32
17348     0/imm32/next
17349     0/imm32/next
17350 
17351 Int-var-in-esi:  # (payload list var)
17352     0x11/imm32/alloc-id:fake:payload
17353     0/imm32/name
17354     0/imm32/name
17355     0x11/imm32/alloc-id:fake
17356     Type-int/imm32
17357     1/imm32/some-block-depth
17358     0/imm32/no-stack-offset
17359     0x11/imm32/alloc-id:fake
17360     $Register-esi/imm32/register
17361 
17362 Single-int-var-in-edi:  # (payload list var)
17363     0x11/imm32/alloc-id:fake:payload
17364     0x11/imm32/alloc-id:fake
17365     Int-var-in-edi/imm32
17366     0/imm32/next
17367     0/imm32/next
17368 
17369 Int-var-in-edi:  # (payload list var)
17370     0x11/imm32/alloc-id:fake:payload
17371     0/imm32/name
17372     0/imm32/name
17373     0x11/imm32/alloc-id:fake
17374     Type-int/imm32
17375     1/imm32/some-block-depth
17376     0/imm32/no-stack-offset
17377     0x11/imm32/alloc-id:fake
17378     $Register-edi/imm32/register
17379 
17380 Single-lit-var:  # (payload list var)
17381     0x11/imm32/alloc-id:fake:payload
17382     0x11/imm32/alloc-id:fake
17383     Lit-var/imm32
17384     0/imm32/next
17385     0/imm32/next
17386 
17387 Lit-var:  # (payload var)
17388     0x11/imm32/alloc-id:fake:payload
17389     0/imm32/name
17390     0/imm32/name
17391     0x11/imm32/alloc-id:fake
17392     Type-literal/imm32
17393     1/imm32/some-block-depth
17394     0/imm32/no-stack-offset
17395     0/imm32/no-register
17396     0/imm32/no-register
17397 
17398 Type-int:  # (payload type-tree)
17399     0x11/imm32/alloc-id:fake:payload
17400     1/imm32/left-is-atom
17401     1/imm32/value:int
17402     0/imm32/left:unused
17403     0/imm32/right:null
17404     0/imm32/right:null
17405 
17406 Type-literal:  # (payload type-tree)
17407     0x11/imm32/alloc-id:fake:payload
17408     1/imm32/is-atom
17409     0/imm32/value:literal
17410     0/imm32/left:unused
17411     0/imm32/right:null
17412     0/imm32/right:null
17413 
17414 Type-addr:  # (payload type-tree)
17415     0x11/imm32/alloc-id:fake:payload
17416     1/imm32/is-atom
17417     2/imm32/value:addr
17418     0/imm32/left:unused
17419     0/imm32/right:null
17420     0/imm32/right:null
17421 
17422 Type-byte:  # (payload type-tree)
17423     0x11/imm32/alloc-id:fake:payload
17424     1/imm32/is-atom
17425     8/imm32/value:byte
17426     0/imm32/left:unused
17427     0/imm32/right:null
17428     0/imm32/right:null
17429 
17430 == code
17431 emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
17432     # . prologue
17433     55/push-ebp
17434     89/<- %ebp 4/r32/esp
17435     # . save registers
17436     50/push-eax
17437     51/push-ecx
17438     # ecx = primitive
17439     8b/-> *(ebp+0x10) 1/r32/ecx
17440     # emit primitive name
17441     (emit-indent *(ebp+8) *Curr-block-depth)
17442     (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
17443     (write-buffered *(ebp+8) %eax)
17444     # emit rm32 if necessary
17445     (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
17446     # emit r32 if necessary
17447     (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
17448     # emit imm32 if necessary
17449     (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
17450     # emit disp32 if necessary
17451     (emit-subx-disp32 *(ebp+8) *(ecx+0x2c) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
17452     (write-buffered *(ebp+8) Newline)
17453 $emit-subx-primitive:end:
17454     # . restore registers
17455     59/pop-to-ecx
17456     58/pop-to-eax
17457     # . epilogue
17458     89/<- %esp 5/r32/ebp
17459     5d/pop-to-ebp
17460     c3/return
17461 
17462 emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17463     # . prologue
17464     55/push-ebp
17465     89/<- %ebp 4/r32/esp
17466     # . save registers
17467     50/push-eax
17468     # if (l == 0) return
17469     81 7/subop/compare *(ebp+0xc) 0/imm32
17470     74/jump-if-= $emit-subx-rm32:end/disp8
17471     # var v/eax: (addr stmt-var)
17472     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
17473     (emit-subx-var-as-rm32 *(ebp+8) %eax)
17474 $emit-subx-rm32:end:
17475     # . restore registers
17476     58/pop-to-eax
17477     # . epilogue
17478     89/<- %esp 5/r32/ebp
17479     5d/pop-to-ebp
17480     c3/return
17481 
17482 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)
17483     # . prologue
17484     55/push-ebp
17485     89/<- %ebp 4/r32/esp
17486     # . save registers
17487     51/push-ecx
17488     # eax = l
17489     8b/-> *(ebp+0xc) 0/r32/eax
17490     # ecx = stmt
17491     8b/-> *(ebp+8) 1/r32/ecx
17492     # if (l == 1) return stmt->inouts
17493     {
17494       3d/compare-eax-and 1/imm32
17495       75/jump-if-!= break/disp8
17496 $get-stmt-operand-from-arg-location:1:
17497       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17498       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17499     }
17500     # if (l == 2) return stmt->inouts->next
17501     {
17502       3d/compare-eax-and 2/imm32
17503       75/jump-if-!= break/disp8
17504 $get-stmt-operand-from-arg-location:2:
17505       (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17506       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17507       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17508     }
17509     # if (l == 3) return stmt->outputs
17510     {
17511       3d/compare-eax-and 3/imm32
17512       75/jump-if-!= break/disp8
17513 $get-stmt-operand-from-arg-location:3:
17514       (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
17515       eb/jump $get-stmt-operand-from-arg-location:end/disp8
17516     }
17517     # abort
17518     e9/jump $get-stmt-operand-from-arg-location:abort/disp32
17519 $get-stmt-operand-from-arg-location:end:
17520     # . restore registers
17521     59/pop-to-ecx
17522     # . epilogue
17523     89/<- %esp 5/r32/ebp
17524     5d/pop-to-ebp
17525     c3/return
17526 
17527 $get-stmt-operand-from-arg-location:abort:
17528     # error("invalid arg-location " eax)
17529     (write-buffered *(ebp+0x10) "invalid arg-location ")
17530     (write-int32-hex-buffered *(ebp+0x10) %eax)
17531     (write-buffered *(ebp+0x10) Newline)
17532     (flush *(ebp+0x10))
17533     (stop *(ebp+0x14) 1)
17534     # never gets here
17535 
17536 emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
17537     # . prologue
17538     55/push-ebp
17539     89/<- %ebp 4/r32/esp
17540     # . save registers
17541     50/push-eax
17542     51/push-ecx
17543     # if (l == 0) return
17544     81 7/subop/compare *(ebp+0xc) 0/imm32
17545     0f 84/jump-if-= $emit-subx-r32:end/disp32
17546     # var v/eax: (addr stmt-var)
17547     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
17548     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17549     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
17550     (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
17551     (write-buffered *(ebp+8) Space)
17552     (write-int32-hex-buffered *(ebp+8) *eax)
17553     (write-buffered *(ebp+8) "/r32")
17554 $emit-subx-r32:end:
17555     # . restore registers
17556     59/pop-to-ecx
17557     58/pop-to-eax
17558     # . epilogue
17559     89/<- %esp 5/r32/ebp
17560     5d/pop-to-ebp
17561     c3/return
17562 
17563 emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
17564     # . prologue
17565     55/push-ebp
17566     89/<- %ebp 4/r32/esp
17567     # . save registers
17568     50/push-eax
17569     51/push-ecx
17570     # if (l == 0) return
17571     81 7/subop/compare *(ebp+0xc) 0/imm32
17572     0f 84/jump-if-= $emit-subx-imm32:end/disp32
17573     # var v/eax: (handle var)
17574     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
17575     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17576     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17577     (write-buffered *(ebp+8) Space)
17578     (write-buffered *(ebp+8) %eax)
17579     (write-buffered *(ebp+8) "/imm32")
17580 $emit-subx-imm32:end:
17581     # . restore registers
17582     59/pop-to-ecx
17583     58/pop-to-eax
17584     # . epilogue
17585     89/<- %esp 5/r32/ebp
17586     5d/pop-to-ebp
17587     c3/return
17588 
17589 emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
17590     # . prologue
17591     55/push-ebp
17592     89/<- %ebp 4/r32/esp
17593     # . save registers
17594     50/push-eax
17595     51/push-ecx
17596     # if (location == 0) return
17597     81 7/subop/compare *(ebp+0xc) 0/imm32
17598     0f 84/jump-if-= $emit-subx-disp32:end/disp32
17599     # var v/eax: (addr stmt-var)
17600     (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
17601     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
17602     (lookup *eax *(eax+4))  # Var-name Var-name => eax
17603     (write-buffered *(ebp+8) Space)
17604     (write-buffered *(ebp+8) %eax)
17605     # hack: if instruction operation starts with "break", emit ":break"
17606     # var name/ecx: (addr array byte) = lookup(stmt->operation)
17607     8b/-> *(ebp+0x10) 0/r32/eax
17608     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
17609     89/<- %ecx 0/r32/eax
17610     {
17611       (string-starts-with? %ecx "break")  # => eax
17612       3d/compare-eax-and 0/imm32/false
17613       74/jump-if-= break/disp8
17614       (write-buffered *(ebp+8) ":break")
17615     }
17616     # hack: if instruction operation starts with "loop", emit ":loop"
17617     {
17618       (string-starts-with? %ecx "loop")  # => eax
17619       3d/compare-eax-and 0/imm32/false
17620       74/jump-if-= break/disp8
17621       (write-buffered *(ebp+8) ":loop")
17622     }
17623     (write-buffered *(ebp+8) "/disp32")
17624 $emit-subx-disp32:end:
17625     # . restore registers
17626     59/pop-to-ecx
17627     58/pop-to-eax
17628     # . epilogue
17629     89/<- %esp 5/r32/ebp
17630     5d/pop-to-ebp
17631     c3/return
17632 
17633 emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
17634     # . prologue
17635     55/push-ebp
17636     89/<- %ebp 4/r32/esp
17637     # . save registers
17638     50/push-eax
17639     51/push-ecx
17640     #
17641     (emit-indent *(ebp+8) *Curr-block-depth)
17642     (write-buffered *(ebp+8) "(")
17643     # ecx = stmt
17644     8b/-> *(ebp+0xc) 1/r32/ecx
17645     # - emit function name
17646     (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
17647     (write-buffered *(ebp+8) %eax)
17648     # - emit arguments
17649     # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
17650     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17651     {
17652       # if (curr == null) break
17653       3d/compare-eax-and 0/imm32
17654       74/jump-if-= break/disp8
17655       #
17656       (emit-subx-call-operand *(ebp+8) %eax)
17657       # curr = lookup(curr->next)
17658       (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
17659       eb/jump loop/disp8
17660     }
17661     #
17662     (write-buffered *(ebp+8) ")\n")
17663 $emit-call:end:
17664     # . restore registers
17665     59/pop-to-ecx
17666     58/pop-to-eax
17667     # . epilogue
17668     89/<- %esp 5/r32/ebp
17669     5d/pop-to-ebp
17670     c3/return
17671 
17672 emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
17673     # shares code with emit-subx-var-as-rm32
17674     # . prologue
17675     55/push-ebp
17676     89/<- %ebp 4/r32/esp
17677     # . save registers
17678     50/push-eax
17679     51/push-ecx
17680     56/push-esi
17681     # ecx = s
17682     8b/-> *(ebp+0xc) 1/r32/ecx
17683     # var operand/esi: (addr var) = lookup(s->value)
17684     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
17685     89/<- %esi 0/r32/eax
17686     # if (operand->register && !s->is-deref?) emit "%__"
17687     {
17688 $emit-subx-call-operand:check-for-register-direct:
17689       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17690       74/jump-if-= break/disp8
17691       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17692       75/jump-if-!= break/disp8
17693 $emit-subx-call-operand:register-direct:
17694       (write-buffered *(ebp+8) " %")
17695       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17696       (write-buffered *(ebp+8) %eax)
17697       e9/jump $emit-subx-call-operand:end/disp32
17698     }
17699     # else if (operand->register && s->is-deref?) emit "*__"
17700     {
17701 $emit-subx-call-operand:check-for-register-indirect:
17702       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17703       74/jump-if-= break/disp8
17704       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17705       74/jump-if-= break/disp8
17706 $emit-subx-call-operand:register-indirect:
17707       (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
17708       e9/jump $emit-subx-call-operand:end/disp32
17709     }
17710     # else if (operand->stack-offset) emit "*(ebp+__)"
17711     {
17712       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
17713       74/jump-if-= break/disp8
17714 $emit-subx-call-operand:stack:
17715       (emit-subx-call-operand-stack *(ebp+8) %esi)
17716       e9/jump $emit-subx-call-operand:end/disp32
17717     }
17718     # else if (operand->type == literal) emit "__"
17719     {
17720       (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
17721       81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
17722       75/jump-if-!= break/disp8
17723 $emit-subx-call-operand:literal:
17724       (write-buffered *(ebp+8) Space)
17725       (lookup *esi *(esi+4))  # Var-name Var-name => eax
17726       (write-buffered *(ebp+8) %eax)
17727     }
17728 $emit-subx-call-operand:end:
17729     # . restore registers
17730     5e/pop-to-esi
17731     59/pop-to-ecx
17732     58/pop-to-eax
17733     # . epilogue
17734     89/<- %esp 5/r32/ebp
17735     5d/pop-to-ebp
17736     c3/return
17737 
17738 emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
17739     # . prologue
17740     55/push-ebp
17741     89/<- %ebp 4/r32/esp
17742     # . save registers
17743     50/push-eax
17744     51/push-ecx
17745     56/push-esi
17746     # esi = v
17747     8b/-> *(ebp+0xc) 6/r32/esi
17748     # var size/ecx: int = size-of-deref(v)
17749     (size-of-deref %esi)  # => eax
17750     89/<- %ecx 0/r32/eax
17751     # var reg-name/esi: (addr array byte) = lookup(v->register)
17752     (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17753     89/<- %esi 0/r32/eax
17754     # TODO: assert size is a multiple of 4
17755     # var i/eax: int = 0
17756     b8/copy-to-eax 0/imm32
17757     {
17758 $emit-subx-call-operand-register-indirect:loop:
17759       # if (i >= size) break
17760       39/compare %eax 1/r32/ecx
17761       7d/jump-if->= break/disp8
17762       # emit " *(" v->register "+" i ")"
17763       (write-buffered *(ebp+8) " *(")
17764       (write-buffered *(ebp+8) %esi)
17765       (write-buffered *(ebp+8) "+")
17766       (write-int32-hex-buffered *(ebp+8) %eax)
17767       (write-buffered *(ebp+8) ")")
17768       # i += 4
17769       05/add-to-eax 4/imm32
17770       #
17771       eb/jump loop/disp8
17772     }
17773 $emit-subx-call-operand-register-indirect:end:
17774     # . restore registers
17775     5e/pop-to-esi
17776     59/pop-to-ecx
17777     58/pop-to-eax
17778     # . epilogue
17779     89/<- %esp 5/r32/ebp
17780     5d/pop-to-ebp
17781     c3/return
17782 
17783 emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
17784     # . prologue
17785     55/push-ebp
17786     89/<- %ebp 4/r32/esp
17787     # . save registers
17788     50/push-eax
17789     51/push-ecx
17790     56/push-esi
17791     # esi = v
17792     8b/-> *(ebp+0xc) 6/r32/esi
17793     # var curr/ecx: int = v->offset
17794     8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
17795     # var max/eax: int = v->offset + size-of(v)
17796     (size-of %esi)  # => eax
17797     # TODO: assert size is a multiple of 4
17798     01/add-to %eax 1/r32/ecx
17799     {
17800 $emit-subx-call-operand-stack:loop:
17801       # if (curr >= max) break
17802       39/compare %ecx 0/r32/eax
17803       7d/jump-if->= break/disp8
17804       # emit " *(ebp+" curr ")"
17805       (write-buffered *(ebp+8) " *(ebp+")
17806       (write-int32-hex-buffered *(ebp+8) %ecx)
17807       (write-buffered *(ebp+8) ")")
17808       # i += 4
17809       81 0/subop/add %ecx 4/imm32
17810       #
17811       eb/jump loop/disp8
17812     }
17813 $emit-subx-call-operand-stack:end:
17814     # . restore registers
17815     5e/pop-to-esi
17816     59/pop-to-ecx
17817     58/pop-to-eax
17818     # . epilogue
17819     89/<- %esp 5/r32/ebp
17820     5d/pop-to-ebp
17821     c3/return
17822 
17823 emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
17824     # . prologue
17825     55/push-ebp
17826     89/<- %ebp 4/r32/esp
17827     # . save registers
17828     50/push-eax
17829     51/push-ecx
17830     56/push-esi
17831     # ecx = s
17832     8b/-> *(ebp+0xc) 1/r32/ecx
17833     # var operand/esi: (addr var) = lookup(s->value)
17834     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
17835     89/<- %esi 0/r32/eax
17836     # if (operand->register && s->is-deref?) emit "*__"
17837     {
17838 $emit-subx-var-as-rm32:check-for-register-indirect:
17839       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17840       74/jump-if-= break/disp8
17841       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17842       74/jump-if-= break/disp8
17843 $emit-subx-var-as-rm32:register-indirect:
17844       (write-buffered *(ebp+8) " *")
17845       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17846       (write-buffered *(ebp+8) %eax)
17847       e9/jump $emit-subx-var-as-rm32:end/disp32
17848     }
17849     # if (operand->register && !s->is-deref?) emit "%__"
17850     {
17851 $emit-subx-var-as-rm32:check-for-register-direct:
17852       81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
17853       74/jump-if-= break/disp8
17854       81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
17855       75/jump-if-!= break/disp8
17856 $emit-subx-var-as-rm32:register-direct:
17857       (write-buffered *(ebp+8) " %")
17858       (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
17859       (write-buffered *(ebp+8) %eax)
17860       e9/jump $emit-subx-var-as-rm32:end/disp32
17861     }
17862     # else if (operand->stack-offset) emit "*(ebp+__)"
17863     {
17864       81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
17865       74/jump-if-= break/disp8
17866 $emit-subx-var-as-rm32:stack:
17867       (write-buffered *(ebp+8) Space)
17868       (write-buffered *(ebp+8) "*(ebp+")
17869       (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
17870       (write-buffered *(ebp+8) ")")
17871     }
17872 $emit-subx-var-as-rm32:end:
17873     # . restore registers
17874     5e/pop-to-esi
17875     59/pop-to-ecx
17876     58/pop-to-eax
17877     # . epilogue
17878     89/<- %esp 5/r32/ebp
17879     5d/pop-to-ebp
17880     c3/return
17881 
17882 find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
17883     # . prologue
17884     55/push-ebp
17885     89/<- %ebp 4/r32/esp
17886     # . save registers
17887     51/push-ecx
17888     # var curr/ecx: (addr primitive) = primitives
17889     8b/-> *(ebp+8) 1/r32/ecx
17890     {
17891 $find-matching-primitive:loop:
17892       # if (curr == null) break
17893       81 7/subop/compare %ecx 0/imm32
17894       74/jump-if-= break/disp8
17895       # if match(curr, stmt) return curr
17896       {
17897         (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
17898         3d/compare-eax-and 0/imm32/false
17899         74/jump-if-= break/disp8
17900         89/<- %eax 1/r32/ecx
17901         eb/jump $find-matching-primitive:end/disp8
17902       }
17903 $find-matching-primitive:next-primitive:
17904       # curr = curr->next
17905       (lookup *(ecx+0x34) *(ecx+0x38))  # Primitive-next Primitive-next => eax
17906       89/<- %ecx 0/r32/eax
17907       #
17908       e9/jump loop/disp32
17909     }
17910     # return null
17911     b8/copy-to-eax 0/imm32
17912 $find-matching-primitive:end:
17913     # . restore registers
17914     59/pop-to-ecx
17915     # . epilogue
17916     89/<- %esp 5/r32/ebp
17917     5d/pop-to-ebp
17918     c3/return
17919 
17920 mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
17921     # A mu stmt matches a primitive if the name matches, all the inout vars
17922     # match, and all the output vars match.
17923     # Vars match if types match and registers match.
17924     # In addition, a stmt output matches a primitive's output if types match
17925     # and the primitive has a wildcard register.
17926     # . prologue
17927     55/push-ebp
17928     89/<- %ebp 4/r32/esp
17929     # . save registers
17930     51/push-ecx
17931     52/push-edx
17932     53/push-ebx
17933     56/push-esi
17934     57/push-edi
17935     # ecx = stmt
17936     8b/-> *(ebp+8) 1/r32/ecx
17937     # edx = primitive
17938     8b/-> *(ebp+0xc) 2/r32/edx
17939     {
17940 $mu-stmt-matches-primitive?:check-name:
17941       # if (primitive->name != stmt->operation) return false
17942       # . var esi: (addr array byte) = lookup(stmt->operation)
17943       (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
17944       89/<- %esi 0/r32/eax
17945       # . var edi: (addr array byte) = lookup(primitive->name)
17946       (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
17947       89/<- %edi 0/r32/eax
17948       (string-equal? %esi %edi)  # => eax
17949       3d/compare-eax-and 0/imm32/false
17950       75/jump-if-!= break/disp8
17951       b8/copy-to-eax 0/imm32
17952       e9/jump $mu-stmt-matches-primitive?:end/disp32
17953     }
17954     # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
17955     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
17956     89/<- %esi 0/r32/eax
17957     # var curr2/edi: (addr list var) = lookup(primitive->inouts)
17958     (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
17959     89/<- %edi 0/r32/eax
17960     {
17961 $mu-stmt-matches-primitive?:inouts-loop:
17962       # if (curr == 0 && curr2 == 0) move on to check outputs
17963       {
17964 $mu-stmt-matches-primitive?:check-both-inouts-null:
17965         81 7/subop/compare %esi 0/imm32
17966         75/jump-if-!= break/disp8
17967 $mu-stmt-matches-primitive?:stmt-inout-null:
17968         81 7/subop/compare %edi 0/imm32
17969         0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
17970 $mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
17971         # return false
17972         b8/copy-to-eax 0/imm32/false
17973         e9/jump $mu-stmt-matches-primitive?:end/disp32
17974       }
17975       # if (curr2 == 0) return false
17976       {
17977 $mu-stmt-matches-primitive?:check-prim-inout-null:
17978         81 7/subop/compare %edi 0/imm32
17979         75/jump-if-!= break/disp8
17980 $mu-stmt-matches-primitive?:prim-inout-null:
17981         b8/copy-to-eax 0/imm32/false
17982         e9/jump $mu-stmt-matches-primitive?:end/disp32
17983       }
17984       # if (curr != curr2) return false
17985       {
17986 $mu-stmt-matches-primitive?:check-inouts-match:
17987         (lookup *edi *(edi+4))  # List-value List-value => eax
17988         (operand-matches-primitive? %esi %eax)  # => eax
17989         3d/compare-eax-and 0/imm32/false
17990         75/jump-if-!= break/disp8
17991 $mu-stmt-matches-primitive?:inouts-match:
17992         b8/copy-to-eax 0/imm32/false
17993         e9/jump $mu-stmt-matches-primitive?:end/disp32
17994       }
17995 $mu-stmt-matches-primitive?:next-inout:
17996       # curr = lookup(curr->next)
17997       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
17998       89/<- %esi 0/r32/eax
17999       # curr2 = lookup(curr2->next)
18000       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
18001       89/<- %edi 0/r32/eax
18002       #
18003       e9/jump loop/disp32
18004     }
18005 $mu-stmt-matches-primitive?:check-outputs:
18006     # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
18007     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
18008     89/<- %esi 0/r32/eax
18009     # var curr2/edi: (addr list var) = lookup(primitive->outputs)
18010     (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
18011     89/<- %edi 0/r32/eax
18012     {
18013 $mu-stmt-matches-primitive?:outputs-loop:
18014       # if (curr == 0) return (curr2 == 0)
18015       {
18016 $mu-stmt-matches-primitive?:check-both-outputs-null:
18017         81 7/subop/compare %esi 0/imm32
18018         75/jump-if-!= break/disp8
18019         {
18020 $mu-stmt-matches-primitive?:stmt-output-null:
18021           81 7/subop/compare %edi 0/imm32
18022           75/jump-if-!= break/disp8
18023 $mu-stmt-matches-primitive?:both-outputs-null:
18024           # return true
18025           b8/copy-to-eax 1/imm32
18026           e9/jump $mu-stmt-matches-primitive?:end/disp32
18027         }
18028 $mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
18029         # return false
18030         b8/copy-to-eax 0/imm32
18031         e9/jump $mu-stmt-matches-primitive?:end/disp32
18032       }
18033       # if (curr2 == 0) return false
18034       {
18035 $mu-stmt-matches-primitive?:check-prim-output-null:
18036         81 7/subop/compare %edi 0/imm32
18037         75/jump-if-!= break/disp8
18038 $mu-stmt-matches-primitive?:prim-output-is-null:
18039         b8/copy-to-eax 0/imm32
18040         e9/jump $mu-stmt-matches-primitive?:end/disp32
18041       }
18042       # if (curr != curr2) return false
18043       {
18044 $mu-stmt-matches-primitive?:check-outputs-match:
18045         (lookup *edi *(edi+4))  # List-value List-value => eax
18046         (operand-matches-primitive? %esi %eax)  # => eax
18047         3d/compare-eax-and 0/imm32/false
18048         75/jump-if-!= break/disp8
18049 $mu-stmt-matches-primitive?:outputs-match:
18050         b8/copy-to-eax 0/imm32
18051         e9/jump $mu-stmt-matches-primitive?:end/disp32
18052       }
18053 $mu-stmt-matches-primitive?:next-output:
18054       # curr = lookup(curr->next)
18055       (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
18056       89/<- %esi 0/r32/eax
18057       # curr2 = lookup(curr2->next)
18058       (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
18059       89/<- %edi 0/r32/eax
18060       #
18061       e9/jump loop/disp32
18062     }
18063 $mu-stmt-matches-primitive?:return-true:
18064     b8/copy-to-eax 1/imm32
18065 $mu-stmt-matches-primitive?:end:
18066     # . restore registers
18067     5f/pop-to-edi
18068     5e/pop-to-esi
18069     5b/pop-to-ebx
18070     5a/pop-to-edx
18071     59/pop-to-ecx
18072     # . epilogue
18073     89/<- %esp 5/r32/ebp
18074     5d/pop-to-ebp
18075     c3/return
18076 
18077 operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
18078     # . prologue
18079     55/push-ebp
18080     89/<- %ebp 4/r32/esp
18081     # . save registers
18082     51/push-ecx
18083     52/push-edx
18084     53/push-ebx
18085     56/push-esi
18086     57/push-edi
18087     # ecx = s
18088     8b/-> *(ebp+8) 1/r32/ecx
18089     # var var/esi: (addr var) = lookup(s->value)
18090     (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
18091     89/<- %esi 0/r32/eax
18092     # edi = prim-var
18093     8b/-> *(ebp+0xc) 7/r32/edi
18094 $operand-matches-primitive?:check-type:
18095     # if !category-match?(var->type, prim-var->type) return false
18096     # . var vtype/ebx: (addr type-tree) = lookup(var->type)
18097     (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
18098     89/<- %ebx 0/r32/eax
18099     # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
18100     (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
18101     (subx-type-category-match? %ebx %eax)  # => eax
18102     3d/compare-eax-and 0/imm32/false
18103     0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
18104     {
18105 $operand-matches-primitive?:check-register:
18106       # if prim-var is in memory and var is in register but dereference, match
18107       {
18108         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
18109         0f 85/jump-if-!= break/disp32
18110         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
18111         74/jump-if-= break/disp8
18112         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
18113         74/jump-if-= break/disp8
18114 $operand-matches-primitive?:var-deref-match:
18115         e9/jump $operand-matches-primitive?:return-true/disp32
18116       }
18117       # if prim-var is in register and var is in register but dereference, no match
18118       {
18119         81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
18120         0f 84/jump-if-= break/disp32
18121         81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
18122         0f 84/jump-if-= break/disp32
18123         81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
18124         74/jump-if-= break/disp8
18125 $operand-matches-primitive?:var-deref-no-match:
18126         e9/jump $operand-matches-primitive?:return-false/disp32
18127       }
18128       # return false if var->register doesn't match prim-var->register
18129       {
18130         # if register addresses are equal, it's a match
18131         # var vreg/ebx: (addr array byte) = lookup(var->register)
18132         (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
18133         89/<- %ebx 0/r32/eax
18134         # var preg/ecx: (addr array byte) = lookup(prim-var->register)
18135         (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
18136         89/<- %ecx 0/r32/eax
18137         # if (vreg == preg) break
18138         39/compare %ecx 3/r32/ebx
18139         74/jump-if-= break/disp8
18140 $operand-matches-primitive?:var-register-no-match:
18141         # if either address is 0, return false
18142         81 7/subop/compare %ebx 0/imm32
18143         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
18144         81 7/subop/compare %ecx 0/imm32
18145         74/jump-if-=  $operand-matches-primitive?:return-false/disp8
18146         # if prim-var->register is wildcard, it's a match
18147         (string-equal? %ecx "*")  # Any-register => eax
18148         3d/compare-eax-and 0/imm32/false
18149         75/jump-if-!= break/disp8
18150 $operand-matches-primitive?:wildcard-no-match:
18151         # if string contents aren't equal, return false
18152         (string-equal? %ecx %ebx)  # => eax
18153         3d/compare-eax-and 0/imm32/false
18154         74/jump-if-= $operand-matches-primitive?:return-false/disp8
18155       }
18156     }
18157 $operand-matches-primitive?:return-true:
18158     b8/copy-to-eax 1/imm32/true
18159     eb/jump $operand-matches-primitive?:end/disp8
18160 $operand-matches-primitive?:return-false:
18161     b8/copy-to-eax 0/imm32/false
18162 $operand-matches-primitive?:end:
18163     # . restore registers
18164     5f/pop-to-edi
18165     5e/pop-to-esi
18166     5b/pop-to-ebx
18167     5a/pop-to-edx
18168     59/pop-to-ecx
18169     # . epilogue
18170     89/<- %esp 5/r32/ebp
18171     5d/pop-to-ebp
18172     c3/return
18173 
18174 find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
18175     # . prologue
18176     55/push-ebp
18177     89/<- %ebp 4/r32/esp
18178     # . save registers
18179     51/push-ecx
18180     # var curr/ecx: (handle function) = functions
18181     8b/-> *(ebp+8) 1/r32/ecx
18182     {
18183       # if (curr == null) break
18184       81 7/subop/compare %ecx 0/imm32
18185       74/jump-if-= break/disp8
18186 #?       (write-buffered Stderr "iter\n")
18187 #?       (flush Stderr)
18188       # if match(stmt, curr) return curr
18189       {
18190         (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
18191         3d/compare-eax-and 0/imm32/false
18192         74/jump-if-= break/disp8
18193         89/<- %eax 1/r32/ecx
18194         eb/jump $find-matching-function:end/disp8
18195       }
18196       # curr = curr->next
18197       (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
18198       89/<- %ecx 0/r32/eax
18199       #
18200       eb/jump loop/disp8
18201     }
18202     # return null
18203     b8/copy-to-eax 0/imm32
18204 $find-matching-function:end:
18205     # . restore registers
18206     59/pop-to-ecx
18207     # . epilogue
18208     89/<- %esp 5/r32/ebp
18209     5d/pop-to-ebp
18210     c3/return
18211 
18212 # Just compare names; user-defined functions don't support overloading yet.
18213 mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
18214     # . prologue
18215     55/push-ebp
18216     89/<- %ebp 4/r32/esp
18217     # . save registers
18218     51/push-ecx
18219     # return function->name == stmt->operation
18220     # ecx = lookup(stmt->operation)
18221     8b/-> *(ebp+8) 0/r32/eax
18222     (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
18223     89/<- %ecx 0/r32/eax
18224     # eax = lookup(function->name)
18225     8b/-> *(ebp+0xc) 0/r32/eax
18226     (lookup *eax *(eax+4))  # Function-name Function-name => eax
18227     (string-equal? %eax %ecx)  # => eax
18228 $mu-stmt-matches-function?:end:
18229     # . restore registers
18230     59/pop-to-ecx
18231     # . epilogue
18232     89/<- %esp 5/r32/ebp
18233     5d/pop-to-ebp
18234     c3/return
18235 
18236 # Type-checking happens elsewhere. This method is for selecting between
18237 # primitives.
18238 subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
18239     # . prologue
18240     55/push-ebp
18241     89/<- %ebp 4/r32/esp
18242     # . save registers
18243     51/push-ecx
18244     # var alit/ecx: boolean = is-literal-type?(a)
18245     (is-simple-mu-type? *(ebp+8) 0)  # => eax
18246     89/<- %ecx 0/r32/eax
18247     # var blit/eax: boolean = is-literal-type?(b)
18248     (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
18249     # return alit == blit
18250     39/compare %eax 1/r32/ecx
18251     0f 94/set-byte-if-= %al
18252     81 4/subop/and %eax 0xff/imm32
18253 $subx-type-category-match?:end:
18254     # . restore registers
18255     59/pop-to-ecx
18256     # . epilogue
18257     89/<- %esp 5/r32/ebp
18258     5d/pop-to-ebp
18259     c3/return
18260 
18261 is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
18262     # . prologue
18263     55/push-ebp
18264     89/<- %ebp 4/r32/esp
18265     # . save registers
18266     51/push-ecx
18267     # ecx = n
18268     8b/-> *(ebp+0xc) 1/r32/ecx
18269     # return (a->value == n)
18270     8b/-> *(ebp+8) 0/r32/eax
18271     39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
18272     0f 94/set-byte-if-= %al
18273     81 4/subop/and %eax 0xff/imm32
18274 $is-simple-mu-type?:end:
18275     # . restore registers
18276     59/pop-to-ecx
18277     # . epilogue
18278     89/<- %esp 5/r32/ebp
18279     5d/pop-to-ebp
18280     c3/return
18281 
18282 is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
18283     # . prologue
18284     55/push-ebp
18285     89/<- %ebp 4/r32/esp
18286     # eax = a
18287     8b/-> *(ebp+8) 0/r32/eax
18288     # if (!a->is-atom?) a = a->left
18289     81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
18290     {
18291       75/jump-if-!= break/disp8
18292       (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
18293     }
18294     # return (a->value == addr)
18295     81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
18296     0f 94/set-byte-if-= %al
18297     81 4/subop/and %eax 0xff/imm32
18298 $is-mu-addr-type?:end:
18299     # . epilogue
18300     89/<- %esp 5/r32/ebp
18301     5d/pop-to-ebp
18302     c3/return
18303 
18304 test-emit-subx-stmt-primitive:
18305     # Primitive operation on a variable on the stack.
18306     #   increment foo
18307     # =>
18308     #   ff 0/subop/increment *(ebp-8)
18309     #
18310     # There's a variable on the var stack as follows:
18311     #   name: 'foo'
18312     #   type: int
18313     #   stack-offset: -8
18314     #
18315     # There's a primitive with this info:
18316     #   name: 'increment'
18317     #   inouts: int/mem
18318     #   value: 'ff 0/subop/increment'
18319     #
18320     # . prologue
18321     55/push-ebp
18322     89/<- %ebp 4/r32/esp
18323     # setup
18324     (clear-stream _test-output-stream)
18325     (clear-stream $_test-output-buffered-file->buffer)
18326     # simulate allocated payloads starting with an initial fake alloc-id (0x11)
18327 $test-emit-subx-stmt-primitive:initialize-type:
18328     # var type/ecx: (payload type-tree) = int
18329     68/push 0/imm32/right:null
18330     68/push 0/imm32/right:null
18331     68/push 0/imm32/left:unused
18332     68/push 1/imm32/value:int
18333     68/push 1/imm32/is-atom?:true
18334     68/push 0x11/imm32/alloc-id:fake:payload
18335     89/<- %ecx 4/r32/esp
18336 $test-emit-subx-stmt-primitive:initialize-var:
18337     # var var-foo/ecx: (payload var) = var(type)
18338     68/push 0/imm32/no-register
18339     68/push 0/imm32/no-register
18340     68/push -8/imm32/stack-offset
18341     68/push 1/imm32/block-depth
18342     51/push-ecx/type
18343     68/push 0x11/imm32/alloc-id:fake
18344     68/push 0/imm32/name
18345     68/push 0/imm32/name
18346     68/push 0x11/imm32/alloc-id:fake:payload
18347     89/<- %ecx 4/r32/esp
18348 $test-emit-subx-stmt-primitive:initialize-var-name:
18349     # var-foo->name = "foo"
18350     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18351     (copy-array Heap "foo" %eax)
18352 $test-emit-subx-stmt-primitive:initialize-stmt-var:
18353     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
18354     68/push 0/imm32/is-deref:false
18355     68/push 0/imm32/next
18356     68/push 0/imm32/next
18357     51/push-ecx/var-foo
18358     68/push 0x11/imm32/alloc-id:fake
18359     68/push 0x11/imm32/alloc-id:fake:payload
18360     89/<- %ebx 4/r32/esp
18361 $test-emit-subx-stmt-primitive:initialize-stmt:
18362     # var stmt/esi: (addr statement)
18363     68/push 0/imm32/no-outputs
18364     68/push 0/imm32/no-outputs
18365     53/push-ebx/inouts
18366     68/push 0x11/imm32/alloc-id:fake
18367     68/push 0/imm32/operation
18368     68/push 0/imm32/operation
18369     68/push 1/imm32/tag
18370     89/<- %esi 4/r32/esp
18371 $test-emit-subx-stmt-primitive:initialize-stmt-operation:
18372     # stmt->operation = "increment"
18373     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18374     (copy-array Heap "increment" %eax)
18375 $test-emit-subx-stmt-primitive:initialize-primitive:
18376     # var primitives/ebx: (addr primitive)
18377     68/push 0/imm32/next
18378     68/push 0/imm32/next
18379     68/push 0/imm32/output-is-write-only
18380     68/push 0/imm32/no-disp32
18381     68/push 0/imm32/no-imm32
18382     68/push 0/imm32/no-r32
18383     68/push 1/imm32/rm32-is-first-inout
18384     68/push 0/imm32/subx-name
18385     68/push 0/imm32/subx-name
18386     68/push 0/imm32/no-outputs
18387     68/push 0/imm32/no-outputs
18388     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18389     68/push 0x11/imm32/alloc-id:fake
18390     68/push 0/imm32/name
18391     68/push 0/imm32/name
18392     89/<- %ebx 4/r32/esp
18393 $test-emit-subx-stmt-primitive:initialize-primitive-name:
18394     # primitives->name = "increment"
18395     (copy-array Heap "increment" %ebx)  # Primitive-name
18396 $test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
18397     # primitives->subx-name = "ff 0/subop/increment"
18398     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18399     (copy-array Heap "ff 0/subop/increment" %eax)
18400     # convert
18401     c7 0/subop/copy *Curr-block-depth 0/imm32
18402     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18403     (flush _test-output-buffered-file)
18404 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18410     # check output
18411     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
18412     # . epilogue
18413     89/<- %esp 5/r32/ebp
18414     5d/pop-to-ebp
18415     c3/return
18416 
18417 test-emit-subx-stmt-primitive-register:
18418     # Primitive operation on a variable in a register.
18419     #   foo <- increment
18420     # =>
18421     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18422     #
18423     # There's a variable on the var stack as follows:
18424     #   name: 'foo'
18425     #   type: int
18426     #   register: 'eax'
18427     #
18428     # There's a primitive with this info:
18429     #   name: 'increment'
18430     #   out: int/reg
18431     #   value: 'ff 0/subop/increment'
18432     #
18433     # . prologue
18434     55/push-ebp
18435     89/<- %ebp 4/r32/esp
18436     # setup
18437     (clear-stream _test-output-stream)
18438     (clear-stream $_test-output-buffered-file->buffer)
18439 $test-emit-subx-stmt-primitive-register:initialize-type:
18440     # var type/ecx: (payload type-tree) = int
18441     68/push 0/imm32/right:null
18442     68/push 0/imm32/right:null
18443     68/push 0/imm32/left:unused
18444     68/push 1/imm32/value:int
18445     68/push 1/imm32/is-atom?:true
18446     68/push 0x11/imm32/alloc-id:fake:payload
18447     89/<- %ecx 4/r32/esp
18448 $test-emit-subx-stmt-primitive-register:initialize-var:
18449     # var var-foo/ecx: (payload var)
18450     68/push 0/imm32/register
18451     68/push 0/imm32/register
18452     68/push 0/imm32/no-stack-offset
18453     68/push 1/imm32/block-depth
18454     51/push-ecx
18455     68/push 0x11/imm32/alloc-id:fake
18456     68/push 0/imm32/name
18457     68/push 0/imm32/name
18458     68/push 0x11/imm32/alloc-id:fake:payload
18459     89/<- %ecx 4/r32/esp
18460 $test-emit-subx-stmt-primitive-register:initialize-var-name:
18461     # var-foo->name = "foo"
18462     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18463     (copy-array Heap "foo" %eax)
18464 $test-emit-subx-stmt-primitive-register:initialize-var-register:
18465     # var-foo->register = "eax"
18466     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18467     (copy-array Heap "eax" %eax)
18468 $test-emit-subx-stmt-primitive-register:initialize-stmt-var:
18469     # var operand/ebx: (payload stmt-var)
18470     68/push 0/imm32/is-deref:false
18471     68/push 0/imm32/next
18472     68/push 0/imm32/next
18473     51/push-ecx/var-foo
18474     68/push 0x11/imm32/alloc-id:fake
18475     68/push 0x11/imm32/alloc-id:fake:payload
18476     89/<- %ebx 4/r32/esp
18477 $test-emit-subx-stmt-primitive-register:initialize-stmt:
18478     # var stmt/esi: (addr statement)
18479     53/push-ebx/outputs
18480     68/push 0x11/imm32/alloc-id:fake
18481     68/push 0/imm32/no-inouts
18482     68/push 0/imm32/no-inouts
18483     68/push 0/imm32/operation
18484     68/push 0/imm32/operation
18485     68/push 1/imm32
18486     89/<- %esi 4/r32/esp
18487 $test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
18488     # stmt->operation = "increment"
18489     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18490     (copy-array Heap "increment" %eax)
18491 $test-emit-subx-stmt-primitive-register:initialize-formal-var:
18492     # var formal-var/ebx: (payload var)
18493     68/push 0/imm32/register
18494     68/push 0/imm32/register
18495     68/push 0/imm32/no-stack-offset
18496     68/push 1/imm32/block-depth
18497     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18498     68/push 0x11/imm32/alloc-id:fake
18499     68/push 0/imm32/name
18500     68/push 0/imm32/name
18501     68/push 0x11/imm32/alloc-id:fake:payload
18502     89/<- %ebx 4/r32/esp
18503 $test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
18504     # formal-var->name = "dummy"
18505     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18506     (copy-array Heap "dummy" %eax)
18507 $test-emit-subx-stmt-primitive-register:initialize-formal-register:
18508     # formal-var->register = "*"
18509     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18510     (copy-array Heap "*" %eax)  # Any-register
18511 $test-emit-subx-stmt-primitive-register:initialize-var-list:
18512     # var formal-outputs/ebx: (payload list var)
18513     68/push 0/imm32/next
18514     68/push 0/imm32/next
18515     53/push-ebx/formal-var
18516     68/push 0x11/imm32/alloc-id:fake
18517     68/push 0x11/imm32/alloc-id:fake:payload
18518     89/<- %ebx 4/r32/esp
18519 $test-emit-subx-stmt-primitive-register:initialize-primitive:
18520     # var primitives/ebx: (addr primitive)
18521     68/push 0/imm32/next
18522     68/push 0/imm32/next
18523     68/push 0/imm32/output-is-write-only
18524     68/push 0/imm32/no-disp32
18525     68/push 0/imm32/no-imm32
18526     68/push 0/imm32/no-r32
18527     68/push 3/imm32/rm32-is-first-output
18528     68/push 0/imm32/subx-name
18529     68/push 0/imm32/subx-name
18530     53/push-ebx/outputs
18531     68/push 0x11/imm32/alloc-id:fake
18532     68/push 0/imm32/no-inouts
18533     68/push 0/imm32/no-inouts
18534     68/push 0/imm32/name
18535     68/push 0/imm32/name
18536     89/<- %ebx 4/r32/esp
18537 $test-emit-subx-stmt-primitive-register:initialize-primitive-name:
18538     # primitives->name = "increment"
18539     (copy-array Heap "increment" %ebx)  # Primitive-name
18540 $test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
18541     # primitives->subx-name = "ff 0/subop/increment"
18542     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18543     (copy-array Heap "ff 0/subop/increment" %eax)
18544     # convert
18545     c7 0/subop/copy *Curr-block-depth 0/imm32
18546     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18547     (flush _test-output-buffered-file)
18548 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18554     # check output
18555     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
18556     # . epilogue
18557     89/<- %esp 5/r32/ebp
18558     5d/pop-to-ebp
18559     c3/return
18560 
18561 test-emit-subx-stmt-select-primitive:
18562     # Select the right primitive between overloads.
18563     #   foo <- increment
18564     # =>
18565     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18566     #
18567     # There's a variable on the var stack as follows:
18568     #   name: 'foo'
18569     #   type: int
18570     #   register: 'eax'
18571     #
18572     # There's two primitives, as follows:
18573     #   - name: 'increment'
18574     #     out: int/reg
18575     #     value: 'ff 0/subop/increment'
18576     #   - name: 'increment'
18577     #     inout: int/mem
18578     #     value: 'ff 0/subop/increment'
18579     #
18580     # . prologue
18581     55/push-ebp
18582     89/<- %ebp 4/r32/esp
18583     # setup
18584     (clear-stream _test-output-stream)
18585     (clear-stream $_test-output-buffered-file->buffer)
18586 $test-emit-subx-stmt-select-primitive:initialize-type:
18587     # var type/ecx: (payload type-tree) = int
18588     68/push 0/imm32/right:null
18589     68/push 0/imm32/right:null
18590     68/push 0/imm32/left:unused
18591     68/push 1/imm32/value:int
18592     68/push 1/imm32/is-atom?:true
18593     68/push 0x11/imm32/alloc-id:fake:payload
18594     89/<- %ecx 4/r32/esp
18595 $test-emit-subx-stmt-select-primitive:initialize-var:
18596     # var var-foo/ecx: (payload var)
18597     68/push 0/imm32/register
18598     68/push 0/imm32/register
18599     68/push 0/imm32/no-stack-offset
18600     68/push 1/imm32/block-depth
18601     51/push-ecx
18602     68/push 0x11/imm32/alloc-id:fake
18603     68/push 0/imm32/name
18604     68/push 0/imm32/name
18605     68/push 0x11/imm32/alloc-id:fake:payload
18606     89/<- %ecx 4/r32/esp
18607 $test-emit-subx-stmt-select-primitive:initialize-var-name:
18608     # var-foo->name = "foo"
18609     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18610     (copy-array Heap "foo" %eax)
18611 $test-emit-subx-stmt-select-primitive:initialize-var-register:
18612     # var-foo->register = "eax"
18613     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18614     (copy-array Heap "eax" %eax)
18615 $test-emit-subx-stmt-select-primitive:initialize-stmt-var:
18616     # var operand/ebx: (payload stmt-var)
18617     68/push 0/imm32/is-deref:false
18618     68/push 0/imm32/next
18619     68/push 0/imm32/next
18620     51/push-ecx/var-foo
18621     68/push 0x11/imm32/alloc-id:fake
18622     68/push 0x11/imm32/alloc-id:fake:payload
18623     89/<- %ebx 4/r32/esp
18624 $test-emit-subx-stmt-select-primitive:initialize-stmt:
18625     # var stmt/esi: (addr statement)
18626     53/push-ebx/outputs
18627     68/push 0x11/imm32/alloc-id:fake
18628     68/push 0/imm32/no-inouts
18629     68/push 0/imm32/no-inouts
18630     68/push 0/imm32/operation
18631     68/push 0/imm32/operation
18632     68/push 1/imm32
18633     89/<- %esi 4/r32/esp
18634 $test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
18635     # stmt->operation = "increment"
18636     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18637     (copy-array Heap "increment" %eax)
18638 $test-emit-subx-stmt-select-primitive:initialize-formal-var:
18639     # var formal-var/ebx: (payload var)
18640     68/push 0/imm32/register
18641     68/push 0/imm32/register
18642     68/push 0/imm32/no-stack-offset
18643     68/push 1/imm32/block-depth
18644     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18645     68/push 0x11/imm32/alloc-id:fake
18646     68/push 0/imm32/name
18647     68/push 0/imm32/name
18648     68/push 0x11/imm32/alloc-id:fake:payload
18649     89/<- %ebx 4/r32/esp
18650 $test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
18651     # formal-var->name = "dummy"
18652     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18653     (copy-array Heap "dummy" %eax)
18654 $test-emit-subx-stmt-select-primitive:initialize-formal-register:
18655     # formal-var->register = "*"
18656     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18657     (copy-array Heap "*" %eax)  # Any-register
18658 $test-emit-subx-stmt-select-primitive:initialize-var-list:
18659     # var formal-outputs/ebx: (payload list var)
18660     68/push 0/imm32/next
18661     68/push 0/imm32/next
18662     53/push-ebx/formal-var
18663     68/push 0x11/imm32/alloc-id:fake
18664     68/push 0x11/imm32/alloc-id:fake:payload
18665     89/<- %ebx 4/r32/esp
18666 $test-emit-subx-stmt-select-primitive:initialize-primitive2:
18667     # var primitive2/edi: (payload primitive)
18668     68/push 0/imm32/next
18669     68/push 0/imm32/next
18670     68/push 0/imm32/output-is-write-only
18671     68/push 0/imm32/no-disp32
18672     68/push 0/imm32/no-imm32
18673     68/push 0/imm32/no-r32
18674     68/push 3/imm32/rm32-is-first-output
18675     68/push 0/imm32/subx-name
18676     68/push 0/imm32/subx-name
18677     53/push-ebx/outputs
18678     68/push 0x11/imm32/alloc-id:fake
18679     68/push 0/imm32/no-inouts
18680     68/push 0/imm32/no-inouts
18681     68/push 0/imm32/name
18682     68/push 0/imm32/name
18683     68/push 0x11/imm32/alloc-id:fake:payload
18684     89/<- %edi 4/r32/esp
18685 $test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
18686     # primitives->name = "increment"
18687     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
18688     (copy-array Heap "increment" %eax)
18689 $test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
18690     # primitives->subx-name = "ff 0/subop/increment"
18691     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
18692     (copy-array Heap "ff 0/subop/increment" %eax)
18693 $test-emit-subx-stmt-select-primitive:initialize-primitive:
18694     # var primitives/ebx: (addr primitive)
18695     57/push-edi
18696     68/push 0x11/imm32/alloc-id:fake
18697     68/push 0/imm32/output-is-write-only
18698     68/push 0/imm32/no-disp32
18699     68/push 0/imm32/no-imm32
18700     68/push 0/imm32/no-r32
18701     68/push 1/imm32/rm32-is-first-inout
18702     68/push 0/imm32/subx-name
18703     68/push 0/imm32/subx-name
18704     68/push 0/imm32/no-outputs
18705     68/push 0/imm32/no-outputs
18706     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18707     68/push 0x11/imm32/alloc-id:fake
18708     68/push 0/imm32/name
18709     68/push 0/imm32/name
18710     89/<- %ebx 4/r32/esp
18711 $test-emit-subx-stmt-select-primitive:initialize-primitive-name:
18712     # primitives->name = "increment"
18713     (copy-array Heap "increment" %ebx)  # Primitive-name
18714 $test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
18715     # primitives->subx-name = "ff 0/subop/increment"
18716     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18717     (copy-array Heap "ff 0/subop/increment" %eax)
18718     # convert
18719     c7 0/subop/copy *Curr-block-depth 0/imm32
18720     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18721     (flush _test-output-buffered-file)
18722 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18728     # check output
18729     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
18730     # . epilogue
18731     89/<- %esp 5/r32/ebp
18732     5d/pop-to-ebp
18733     c3/return
18734 
18735 test-emit-subx-stmt-select-primitive-2:
18736     # Select the right primitive between overloads.
18737     #   increment foo
18738     # =>
18739     #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
18740     #
18741     # There's a variable on the var stack as follows:
18742     #   name: 'foo'
18743     #   type: int
18744     #   register: 'eax'
18745     #
18746     # There's two primitives, as follows:
18747     #   - name: 'increment'
18748     #     out: int/reg
18749     #     value: 'ff 0/subop/increment'
18750     #   - name: 'increment'
18751     #     inout: int/mem
18752     #     value: 'ff 0/subop/increment'
18753     #
18754     # . prologue
18755     55/push-ebp
18756     89/<- %ebp 4/r32/esp
18757     # setup
18758     (clear-stream _test-output-stream)
18759     (clear-stream $_test-output-buffered-file->buffer)
18760 $test-emit-subx-stmt-select-primitive-2:initialize-type:
18761     # var type/ecx: (payload type-tree) = int
18762     68/push 0/imm32/right:null
18763     68/push 0/imm32/right:null
18764     68/push 0/imm32/left:unused
18765     68/push 1/imm32/value:int
18766     68/push 1/imm32/is-atom?:true
18767     68/push 0x11/imm32/alloc-id:fake:payload
18768     89/<- %ecx 4/r32/esp
18769 $test-emit-subx-stmt-select-primitive-2:initialize-var:
18770     # var var-foo/ecx: (payload var)
18771     68/push 0/imm32/register
18772     68/push 0/imm32/register
18773     68/push 0/imm32/no-stack-offset
18774     68/push 1/imm32/block-depth
18775     51/push-ecx
18776     68/push 0x11/imm32/alloc-id:fake
18777     68/push 0/imm32/name
18778     68/push 0/imm32/name
18779     68/push 0x11/imm32/alloc-id:fake:payload
18780     89/<- %ecx 4/r32/esp
18781 $test-emit-subx-stmt-select-primitive-2:initialize-var-name:
18782     # var-foo->name = "foo"
18783     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18784     (copy-array Heap "foo" %eax)
18785 $test-emit-subx-stmt-select-primitive-2:initialize-var-register:
18786     # var-foo->register = "eax"
18787     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18788     (copy-array Heap "eax" %eax)
18789 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
18790     # var operand/ebx: (payload stmt-var)
18791     68/push 0/imm32/is-deref:false
18792     68/push 0/imm32/next
18793     68/push 0/imm32/next
18794     51/push-ecx/var-foo
18795     68/push 0x11/imm32/alloc-id:fake
18796     68/push 0x11/imm32/alloc-id:fake:payload
18797     89/<- %ebx 4/r32/esp
18798 $test-emit-subx-stmt-select-primitive-2:initialize-stmt:
18799     # var stmt/esi: (addr statement)
18800     68/push 0/imm32/no-outputs
18801     68/push 0/imm32/no-outputs
18802     53/push-ebx/inouts
18803     68/push 0x11/imm32/alloc-id:fake
18804     68/push 0/imm32/operation
18805     68/push 0/imm32/operation
18806     68/push 1/imm32
18807     89/<- %esi 4/r32/esp
18808 $test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
18809     # stmt->operation = "increment"
18810     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18811     (copy-array Heap "increment" %eax)
18812 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
18813     # var formal-var/ebx: (payload var)
18814     68/push 0/imm32/register
18815     68/push 0/imm32/register
18816     68/push 0/imm32/no-stack-offset
18817     68/push 1/imm32/block-depth
18818     ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
18819     68/push 0x11/imm32/alloc-id:fake
18820     68/push 0/imm32/name
18821     68/push 0/imm32/name
18822     68/push 0x11/imm32/alloc-id:fake:payload
18823     89/<- %ebx 4/r32/esp
18824 $test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
18825     # formal-var->name = "dummy"
18826     8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
18827     (copy-array Heap "dummy" %eax)
18828 $test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
18829     # formal-var->register = "*"
18830     8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
18831     (copy-array Heap "*" %eax)  # Any-register
18832 $test-emit-subx-stmt-select-primitive-2:initialize-var-list:
18833     # var formal-outputs/ebx: (payload list stmt-var)
18834     68/push 0/imm32/next
18835     68/push 0/imm32/next
18836     53/push-ebx/formal-var
18837     68/push 0x11/imm32/alloc-id:fake
18838     68/push 0x11/imm32/alloc-id:fake:payload
18839     89/<- %ebx 4/r32/esp
18840 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
18841     # var primitive2/edi: (payload primitive)
18842     68/push 0/imm32/next
18843     68/push 0/imm32/next
18844     68/push 0/imm32/output-is-write-only
18845     68/push 0/imm32/no-disp32
18846     68/push 0/imm32/no-imm32
18847     68/push 0/imm32/no-r32
18848     68/push 3/imm32/rm32-is-first-output
18849     68/push 0/imm32/subx-name
18850     68/push 0/imm32/subx-name
18851     53/push-ebx/outputs
18852     68/push 0x11/imm32/alloc-id:fake
18853     68/push 0/imm32/no-inouts
18854     68/push 0/imm32/no-inouts
18855     68/push 0/imm32/name
18856     68/push 0/imm32/name
18857     68/push 0x11/imm32/alloc-id:fake:payload
18858     89/<- %edi 4/r32/esp
18859 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
18860     # primitives->name = "increment"
18861     8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
18862     (copy-array Heap "increment" %eax)
18863 $test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
18864     # primitives->subx-name = "ff 0/subop/increment"
18865     8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
18866     (copy-array Heap "ff 0/subop/increment" %eax)
18867 $test-emit-subx-stmt-select-primitive-2:initialize-primitive:
18868     # var primitives/ebx: (addr primitive)
18869     57/push-edi
18870     68/push 0x11/imm32/alloc-id:fake
18871     68/push 0/imm32/output-is-write-only
18872     68/push 0/imm32/no-disp32
18873     68/push 0/imm32/no-imm32
18874     68/push 0/imm32/no-r32
18875     68/push 1/imm32/rm32-is-first-inout
18876     68/push 0/imm32/subx-name
18877     68/push 0/imm32/subx-name
18878     68/push 0/imm32/no-outputs
18879     68/push 0/imm32/no-outputs
18880     53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
18881     68/push 0x11/imm32/alloc-id:fake
18882     68/push 0/imm32/name
18883     68/push 0/imm32/name
18884     89/<- %ebx 4/r32/esp
18885 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
18886     # primitives->name = "increment"
18887     (copy-array Heap "increment" %ebx)  # Primitive-name
18888 $test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
18889     # primitives->subx-name = "ff 0/subop/increment"
18890     8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
18891     (copy-array Heap "ff 0/subop/increment" %eax)
18892     # convert
18893     c7 0/subop/copy *Curr-block-depth 0/imm32
18894     (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
18895     (flush _test-output-buffered-file)
18896 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18902     # check output
18903     (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
18904     # . epilogue
18905     89/<- %esp 5/r32/ebp
18906     5d/pop-to-ebp
18907     c3/return
18908 
18909 test-increment-register:
18910     # Select the right register between overloads.
18911     #   foo <- increment
18912     # =>
18913     #   50/increment-eax
18914     #
18915     # There's a variable on the var stack as follows:
18916     #   name: 'foo'
18917     #   type: int
18918     #   register: 'eax'
18919     #
18920     # Primitives are the global definitions.
18921     #
18922     # . prologue
18923     55/push-ebp
18924     89/<- %ebp 4/r32/esp
18925     # setup
18926     (clear-stream _test-output-stream)
18927     (clear-stream $_test-output-buffered-file->buffer)
18928 $test-increment-register:initialize-type:
18929     # var type/ecx: (payload type-tree) = int
18930     68/push 0/imm32/right:null
18931     68/push 0/imm32/right:null
18932     68/push 0/imm32/left:unused
18933     68/push 1/imm32/value:int
18934     68/push 1/imm32/is-atom?:true
18935     68/push 0x11/imm32/alloc-id:fake:payload
18936     89/<- %ecx 4/r32/esp
18937 $test-increment-register:initialize-var:
18938     # var var-foo/ecx: (payload var)
18939     68/push 0/imm32/register
18940     68/push 0/imm32/register
18941     68/push 0/imm32/no-stack-offset
18942     68/push 1/imm32/block-depth
18943     51/push-ecx
18944     68/push 0x11/imm32/alloc-id:fake
18945     68/push 0/imm32/name
18946     68/push 0/imm32/name
18947     68/push 0x11/imm32/alloc-id:fake:payload
18948     89/<- %ecx 4/r32/esp
18949 $test-increment-register:initialize-var-name:
18950     # var-foo->name = "foo"
18951     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
18952     (copy-array Heap "foo" %eax)
18953 $test-increment-register:initialize-var-register:
18954     # var-foo->register = "eax"
18955     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
18956     (copy-array Heap "eax" %eax)
18957 $test-increment-register:initialize-stmt-var:
18958     # var operand/ebx: (payload stmt-var)
18959     68/push 0/imm32/is-deref:false
18960     68/push 0/imm32/next
18961     68/push 0/imm32/next
18962     51/push-ecx/var-foo
18963     68/push 0x11/imm32/alloc-id:fake
18964     68/push 0x11/imm32/alloc-id:fake:payload
18965     89/<- %ebx 4/r32/esp
18966 $test-increment-register:initialize-stmt:
18967     # var stmt/esi: (addr statement)
18968     53/push-ebx/outputs
18969     68/push 0x11/imm32/alloc-id:fake
18970     68/push 0/imm32/no-inouts
18971     68/push 0/imm32/no-inouts
18972     68/push 0/imm32/operation
18973     68/push 0/imm32/operation
18974     68/push 1/imm32
18975     89/<- %esi 4/r32/esp
18976 $test-increment-register:initialize-stmt-operation:
18977     # stmt->operation = "increment"
18978     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
18979     (copy-array Heap "increment" %eax)
18980     # convert
18981     c7 0/subop/copy *Curr-block-depth 0/imm32
18982     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
18983     (flush _test-output-buffered-file)
18984 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
18990     # check output
18991     (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
18992     # . epilogue
18993     89/<- %esp 5/r32/ebp
18994     5d/pop-to-ebp
18995     c3/return
18996 
18997 test-add-reg-to-reg:
18998     #   var1/reg <- add var2/reg
18999     # =>
19000     #   01/add-to %var1 var2
19001     #
19002     # . prologue
19003     55/push-ebp
19004     89/<- %ebp 4/r32/esp
19005     # setup
19006     (clear-stream _test-output-stream)
19007     (clear-stream $_test-output-buffered-file->buffer)
19008 $test-add-reg-to-reg:initialize-type:
19009     # var type/ecx: (payload type-tree) = int
19010     68/push 0/imm32/right:null
19011     68/push 0/imm32/right:null
19012     68/push 0/imm32/left:unused
19013     68/push 1/imm32/value:int
19014     68/push 1/imm32/is-atom?:true
19015     68/push 0x11/imm32/alloc-id:fake:payload
19016     89/<- %ecx 4/r32/esp
19017 $test-add-reg-to-reg:initialize-var1:
19018     # var var1/ecx: (payload var)
19019     68/push 0/imm32/register
19020     68/push 0/imm32/register
19021     68/push 0/imm32/no-stack-offset
19022     68/push 1/imm32/block-depth
19023     51/push-ecx
19024     68/push 0x11/imm32/alloc-id:fake
19025     68/push 0/imm32/name
19026     68/push 0/imm32/name
19027     68/push 0x11/imm32/alloc-id:fake:payload
19028     89/<- %ecx 4/r32/esp
19029 $test-add-reg-to-reg:initialize-var1-name:
19030     # var1->name = "var1"
19031     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19032     (copy-array Heap "var1" %eax)
19033 $test-add-reg-to-reg:initialize-var1-register:
19034     # var1->register = "eax"
19035     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19036     (copy-array Heap "eax" %eax)
19037 $test-add-reg-to-reg:initialize-var2:
19038     # var var2/edx: (payload var)
19039     68/push 0/imm32/register
19040     68/push 0/imm32/register
19041     68/push 0/imm32/no-stack-offset
19042     68/push 1/imm32/block-depth
19043     ff 6/subop/push *(ecx+0x10)
19044     68/push 0x11/imm32/alloc-id:fake
19045     68/push 0/imm32/name
19046     68/push 0/imm32/name
19047     68/push 0x11/imm32/alloc-id:fake:payload
19048     89/<- %edx 4/r32/esp
19049 $test-add-reg-to-reg:initialize-var2-name:
19050     # var2->name = "var2"
19051     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19052     (copy-array Heap "var2" %eax)
19053 $test-add-reg-to-reg:initialize-var2-register:
19054     # var2->register = "ecx"
19055     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19056     (copy-array Heap "ecx" %eax)
19057 $test-add-reg-to-reg:initialize-inouts:
19058     # var inouts/esi: (payload stmt-var) = [var2]
19059     68/push 0/imm32/is-deref:false
19060     68/push 0/imm32/next
19061     68/push 0/imm32/next
19062     52/push-edx/var2
19063     68/push 0x11/imm32/alloc-id:fake
19064     68/push 0x11/imm32/alloc-id:fake:payload
19065     89/<- %esi 4/r32/esp
19066 $test-add-reg-to-reg:initialize-outputs:
19067     # var outputs/edi: (payload stmt-var) = [var1]
19068     68/push 0/imm32/is-deref:false
19069     68/push 0/imm32/next
19070     68/push 0/imm32/next
19071     51/push-ecx/var1
19072     68/push 0x11/imm32/alloc-id:fake
19073     68/push 0x11/imm32/alloc-id:fake:payload
19074     89/<- %edi 4/r32/esp
19075 $test-add-reg-to-reg:initialize-stmt:
19076     # var stmt/esi: (addr statement)
19077     68/push 0/imm32/next
19078     68/push 0/imm32/next
19079     57/push-edi/outputs
19080     68/push 0x11/imm32/alloc-id:fake
19081     56/push-esi/inouts
19082     68/push 0x11/imm32/alloc-id:fake
19083     68/push 0/imm32/operation
19084     68/push 0/imm32/operation
19085     68/push 1/imm32/tag:stmt1
19086     89/<- %esi 4/r32/esp
19087 $test-add-reg-to-reg:initialize-stmt-operation:
19088     # stmt->operation = "add"
19089     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19090     (copy-array Heap "add" %eax)
19091     # convert
19092     c7 0/subop/copy *Curr-block-depth 0/imm32
19093     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19094     (flush _test-output-buffered-file)
19095 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19101     # check output
19102     (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
19103     # . epilogue
19104     89/<- %esp 5/r32/ebp
19105     5d/pop-to-ebp
19106     c3/return
19107 
19108 test-add-reg-to-mem:
19109     #   add-to var1 var2/reg
19110     # =>
19111     #   01/add-to *(ebp+__) var2
19112     #
19113     # . prologue
19114     55/push-ebp
19115     89/<- %ebp 4/r32/esp
19116     # setup
19117     (clear-stream _test-output-stream)
19118     (clear-stream $_test-output-buffered-file->buffer)
19119 $test-add-reg-to-mem:initialize-type:
19120     # var type/ecx: (payload type-tree) = int
19121     68/push 0/imm32/right:null
19122     68/push 0/imm32/right:null
19123     68/push 0/imm32/left:unused
19124     68/push 1/imm32/value:int
19125     68/push 1/imm32/is-atom?:true
19126     68/push 0x11/imm32/alloc-id:fake:payload
19127     89/<- %ecx 4/r32/esp
19128 $test-add-reg-to-mem:initialize-var1:
19129     # var var1/ecx: (payload var)
19130     68/push 0/imm32/register
19131     68/push 0/imm32/register
19132     68/push 8/imm32/stack-offset
19133     68/push 1/imm32/block-depth
19134     51/push-ecx
19135     68/push 0x11/imm32/alloc-id:fake
19136     68/push 0/imm32/name
19137     68/push 0/imm32/name
19138     68/push 0x11/imm32/alloc-id:fake:payload
19139     89/<- %ecx 4/r32/esp
19140 $test-add-reg-to-mem:initialize-var1-name:
19141     # var1->name = "var1"
19142     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19143     (copy-array Heap "var1" %eax)
19144 $test-add-reg-to-mem:initialize-var2:
19145     # var var2/edx: (payload var)
19146     68/push 0/imm32/register
19147     68/push 0/imm32/register
19148     68/push 0/imm32/no-stack-offset
19149     68/push 1/imm32/block-depth
19150     ff 6/subop/push *(ecx+0x10)
19151     68/push 0x11/imm32/alloc-id:fake
19152     68/push 0/imm32/name
19153     68/push 0/imm32/name
19154     68/push 0x11/imm32/alloc-id:fake:payload
19155     89/<- %edx 4/r32/esp
19156 $test-add-reg-to-mem:initialize-var2-name:
19157     # var2->name = "var2"
19158     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19159     (copy-array Heap "var2" %eax)
19160 $test-add-reg-to-mem:initialize-var2-register:
19161     # var2->register = "ecx"
19162     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19163     (copy-array Heap "ecx" %eax)
19164 $test-add-reg-to-mem:initialize-inouts:
19165     # var inouts/esi: (payload stmt-var) = [var2]
19166     68/push 0/imm32/is-deref:false
19167     68/push 0/imm32/next
19168     68/push 0/imm32/next
19169     52/push-edx/var2
19170     68/push 0x11/imm32/alloc-id:fake
19171     68/push 0x11/imm32/alloc-id:fake:payload
19172     89/<- %esi 4/r32/esp
19173     # inouts = [var1, var2]
19174     68/push 0/imm32/is-deref:false
19175     56/push-esi/next
19176     68/push 0x11/imm32/alloc-id:fake
19177     51/push-ecx/var1
19178     68/push 0x11/imm32/alloc-id:fake
19179     68/push 0x11/imm32/alloc-id:fake:payload
19180     89/<- %esi 4/r32/esp
19181 $test-add-reg-to-mem:initialize-stmt:
19182     # var stmt/esi: (addr statement)
19183     68/push 0/imm32/next
19184     68/push 0/imm32/next
19185     68/push 0/imm32/outputs
19186     68/push 0/imm32/outputs
19187     56/push-esi/inouts
19188     68/push 0x11/imm32/alloc-id:fake
19189     68/push 0/imm32/operation
19190     68/push 0/imm32/operation
19191     68/push 1/imm32/tag:stmt1
19192     89/<- %esi 4/r32/esp
19193 $test-add-reg-to-mem:initialize-stmt-operation:
19194     # stmt->operation = "add-to"
19195     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19196     (copy-array Heap "add-to" %eax)
19197     # convert
19198     c7 0/subop/copy *Curr-block-depth 0/imm32
19199     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19200     (flush _test-output-buffered-file)
19201 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19207     # check output
19208     (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
19209     # . epilogue
19210     89/<- %esp 5/r32/ebp
19211     5d/pop-to-ebp
19212     c3/return
19213 
19214 test-add-mem-to-reg:
19215     #   var1/reg <- add var2
19216     # =>
19217     #   03/add *(ebp+__) var1
19218     #
19219     # . prologue
19220     55/push-ebp
19221     89/<- %ebp 4/r32/esp
19222     # setup
19223     (clear-stream _test-output-stream)
19224     (clear-stream $_test-output-buffered-file->buffer)
19225 $test-add-mem-to-reg:initialize-type:
19226     # var type/ecx: (payload type-tree) = int
19227     68/push 0/imm32/right:null
19228     68/push 0/imm32/right:null
19229     68/push 0/imm32/left:unused
19230     68/push 1/imm32/value:int
19231     68/push 1/imm32/is-atom?:true
19232     68/push 0x11/imm32/alloc-id:fake:payload
19233     89/<- %ecx 4/r32/esp
19234 $test-add-mem-to-reg:initialize-var:
19235     # var var1/ecx: (payload var)
19236     68/push 0/imm32/register
19237     68/push 0/imm32/register
19238     68/push 0/imm32/no-stack-offset
19239     68/push 1/imm32/block-depth
19240     51/push-ecx
19241     68/push 0x11/imm32/alloc-id:fake
19242     68/push 0/imm32/name
19243     68/push 0/imm32/name
19244     68/push 0x11/imm32/alloc-id:fake:payload
19245     89/<- %ecx 4/r32/esp
19246 $test-add-mem-to-reg:initialize-var-name:
19247     # var1->name = "foo"
19248     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19249     (copy-array Heap "var1" %eax)
19250 $test-add-mem-to-reg:initialize-var-register:
19251     # var1->register = "eax"
19252     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19253     (copy-array Heap "eax" %eax)
19254 $test-add-mem-to-reg:initialize-var2:
19255     # var var2/edx: (payload var)
19256     68/push 0/imm32/register
19257     68/push 0/imm32/register
19258     68/push 8/imm32/stack-offset
19259     68/push 1/imm32/block-depth
19260     ff 6/subop/push *(ecx+0x10)
19261     68/push 0x11/imm32/alloc-id:fake
19262     68/push 0/imm32/name
19263     68/push 0/imm32/name
19264     68/push 0x11/imm32/alloc-id:fake:payload
19265     89/<- %edx 4/r32/esp
19266 $test-add-mem-to-reg:initialize-var2-name:
19267     # var2->name = "var2"
19268     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19269     (copy-array Heap "var2" %eax)
19270 $test-add-mem-to-reg:initialize-inouts:
19271     # var inouts/esi: (payload stmt-var) = [var2]
19272     68/push 0/imm32/is-deref:false
19273     68/push 0/imm32/next
19274     68/push 0/imm32/next
19275     52/push-edx/var2
19276     68/push 0x11/imm32/alloc-id:fake
19277     68/push 0x11/imm32/alloc-id:fake:payload
19278     89/<- %esi 4/r32/esp
19279 $test-add-mem-to-reg:initialize-outputs:
19280     # var outputs/edi: (payload stmt-var) = [var1]
19281     68/push 0/imm32/is-deref:false
19282     68/push 0/imm32/next
19283     68/push 0/imm32/next
19284     51/push-ecx/var1
19285     68/push 0x11/imm32/alloc-id:fake
19286     68/push 0x11/imm32/alloc-id:fake:payload
19287     89/<- %edi 4/r32/esp
19288 $test-add-mem-to-reg:initialize-stmt:
19289     # var stmt/esi: (addr statement)
19290     68/push 0/imm32/next
19291     68/push 0/imm32/next
19292     57/push-edi/outputs
19293     68/push 0x11/imm32/alloc-id:fake
19294     56/push-esi/inouts
19295     68/push 0x11/imm32/alloc-id:fake
19296     68/push 0/imm32/operation
19297     68/push 0/imm32/operation
19298     68/push 1/imm32/tag:stmt1
19299     89/<- %esi 4/r32/esp
19300 $test-add-mem-to-reg:initialize-stmt-operation:
19301     # stmt->operation = "add"
19302     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19303     (copy-array Heap "add" %eax)
19304     # convert
19305     c7 0/subop/copy *Curr-block-depth 0/imm32
19306     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19307     (flush _test-output-buffered-file)
19308 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19314     # check output
19315     (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
19316     # . epilogue
19317     89/<- %esp 5/r32/ebp
19318     5d/pop-to-ebp
19319     c3/return
19320 
19321 test-add-literal-to-eax:
19322     #   var1/eax <- add 0x34
19323     # =>
19324     #   05/add-to-eax 0x34/imm32
19325     #
19326     # . prologue
19327     55/push-ebp
19328     89/<- %ebp 4/r32/esp
19329     # setup
19330     (clear-stream _test-output-stream)
19331     (clear-stream $_test-output-buffered-file->buffer)
19332 $test-add-literal-to-eax:initialize-var-type:
19333     # var type/ecx: (payload type-tree) = int
19334     68/push 0/imm32/right:null
19335     68/push 0/imm32/right:null
19336     68/push 0/imm32/left:unused
19337     68/push 1/imm32/value:int
19338     68/push 1/imm32/is-atom?:true
19339     68/push 0x11/imm32/alloc-id:fake:payload
19340     89/<- %ecx 4/r32/esp
19341 $test-add-literal-to-eax:initialize-var:
19342     # var v/ecx: (payload var)
19343     68/push 0/imm32/register
19344     68/push 0/imm32/register
19345     68/push 0/imm32/no-stack-offset
19346     68/push 1/imm32/block-depth
19347     51/push-ecx
19348     68/push 0x11/imm32/alloc-id:fake
19349     68/push 0/imm32/name
19350     68/push 0/imm32/name
19351     68/push 0x11/imm32/alloc-id:fake:payload
19352     89/<- %ecx 4/r32/esp
19353 $test-add-literal-to-eax:initialize-var-name:
19354     # v->name = "v"
19355     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19356     (copy-array Heap "v" %eax)
19357 $test-add-literal-to-eax:initialize-var-register:
19358     # v->register = "eax"
19359     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19360     (copy-array Heap "eax" %eax)
19361 $test-add-literal-to-eax:initialize-literal-type:
19362     # var type/edx: (payload type-tree) = literal
19363     68/push 0/imm32/right:null
19364     68/push 0/imm32/right:null
19365     68/push 0/imm32/left:unused
19366     68/push 0/imm32/value:literal
19367     68/push 1/imm32/is-atom?:true
19368     68/push 0x11/imm32/alloc-id:fake:payload
19369     89/<- %edx 4/r32/esp
19370 $test-add-literal-to-eax:initialize-literal:
19371     # var l/edx: (payload var)
19372     68/push 0/imm32/register
19373     68/push 0/imm32/register
19374     68/push 0/imm32/no-stack-offset
19375     68/push 1/imm32/block-depth
19376     52/push-edx
19377     68/push 0x11/imm32/alloc-id:fake
19378     68/push 0/imm32/name
19379     68/push 0/imm32/name
19380     68/push 0x11/imm32/alloc-id:fake:payload
19381     89/<- %edx 4/r32/esp
19382 $test-add-literal-to-eax:initialize-literal-value:
19383     # l->name = "0x34"
19384     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19385     (copy-array Heap "0x34" %eax)
19386 $test-add-literal-to-eax:initialize-inouts:
19387     # var inouts/esi: (payload stmt-var) = [l]
19388     68/push 0/imm32/is-deref:false
19389     68/push 0/imm32/next
19390     68/push 0/imm32/next
19391     52/push-edx/l
19392     68/push 0x11/imm32/alloc-id:fake
19393     68/push 0x11/imm32/alloc-id:fake:payload
19394     89/<- %esi 4/r32/esp
19395 $test-add-literal-to-eax:initialize-outputs:
19396     # var outputs/edi: (payload stmt-var) = [v]
19397     68/push 0/imm32/is-deref:false
19398     68/push 0/imm32/next
19399     68/push 0/imm32/next
19400     51/push-ecx/v
19401     68/push 0x11/imm32/alloc-id:fake
19402     68/push 0x11/imm32/alloc-id:fake:payload
19403     89/<- %edi 4/r32/esp
19404 $test-add-literal-to-eax:initialize-stmt:
19405     # var stmt/esi: (addr statement)
19406     68/push 0/imm32/next
19407     68/push 0/imm32/next
19408     57/push-edi/outputs
19409     68/push 0x11/imm32/alloc-id:fake
19410     56/push-esi/inouts
19411     68/push 0x11/imm32/alloc-id:fake
19412     68/push 0/imm32/operation
19413     68/push 0/imm32/operation
19414     68/push 1/imm32/tag:stmt1
19415     89/<- %esi 4/r32/esp
19416 $test-add-literal-to-eax:initialize-stmt-operation:
19417     # stmt->operation = "add"
19418     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19419     (copy-array Heap "add" %eax)
19420     # convert
19421     c7 0/subop/copy *Curr-block-depth 0/imm32
19422     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19423     (flush _test-output-buffered-file)
19424 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19430     # check output
19431     (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
19432     # . epilogue
19433     89/<- %esp 5/r32/ebp
19434     5d/pop-to-ebp
19435     c3/return
19436 
19437 test-add-literal-to-reg:
19438     #   var1/ecx <- add 0x34
19439     # =>
19440     #   81 0/subop/add %ecx 0x34/imm32
19441     #
19442     # . prologue
19443     55/push-ebp
19444     89/<- %ebp 4/r32/esp
19445     # setup
19446     (clear-stream _test-output-stream)
19447     (clear-stream $_test-output-buffered-file->buffer)
19448 $test-add-literal-to-reg:initialize-var-type:
19449     # var type/ecx: (payload type-tree) = int
19450     68/push 0/imm32/right:null
19451     68/push 0/imm32/right:null
19452     68/push 0/imm32/left:unused
19453     68/push 1/imm32/value:int
19454     68/push 1/imm32/is-atom?:true
19455     68/push 0x11/imm32/alloc-id:fake:payload
19456     89/<- %ecx 4/r32/esp
19457 $test-add-literal-to-reg:initialize-var:
19458     # var v/ecx: (payload var)
19459     68/push 0/imm32/register
19460     68/push 0/imm32/register
19461     68/push 0/imm32/no-stack-offset
19462     68/push 1/imm32/block-depth
19463     51/push-ecx
19464     68/push 0x11/imm32/alloc-id:fake
19465     68/push 0/imm32/name
19466     68/push 0/imm32/name
19467     68/push 0x11/imm32/alloc-id:fake:payload
19468     89/<- %ecx 4/r32/esp
19469 $test-add-literal-to-reg:initialize-var-name:
19470     # v->name = "v"
19471     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19472     (copy-array Heap "v" %eax)
19473 $test-add-literal-to-reg:initialize-var-register:
19474     # v->register = "ecx"
19475     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19476     (copy-array Heap "ecx" %eax)
19477 $test-add-literal-to-reg:initialize-literal-type:
19478     # var type/edx: (payload type-tree) = literal
19479     68/push 0/imm32/right:null
19480     68/push 0/imm32/right:null
19481     68/push 0/imm32/left:unused
19482     68/push 0/imm32/value:literal
19483     68/push 1/imm32/is-atom?:true
19484     68/push 0x11/imm32/alloc-id:fake:payload
19485     89/<- %edx 4/r32/esp
19486 $test-add-literal-to-reg:initialize-literal:
19487     # var l/edx: (payload var)
19488     68/push 0/imm32/register
19489     68/push 0/imm32/register
19490     68/push 0/imm32/no-stack-offset
19491     68/push 1/imm32/block-depth
19492     52/push-edx
19493     68/push 0x11/imm32/alloc-id:fake
19494     68/push 0/imm32/name
19495     68/push 0/imm32/name
19496     68/push 0x11/imm32/alloc-id:fake:payload
19497     89/<- %edx 4/r32/esp
19498 $test-add-literal-to-reg:initialize-literal-value:
19499     # l->name = "0x34"
19500     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19501     (copy-array Heap "0x34" %eax)
19502 $test-add-literal-to-reg:initialize-inouts:
19503     # var inouts/esi: (payload stmt-var) = [l]
19504     68/push 0/imm32/is-deref:false
19505     68/push 0/imm32/next
19506     68/push 0/imm32/next
19507     52/push-edx/l
19508     68/push 0x11/imm32/alloc-id:fake
19509     68/push 0x11/imm32/alloc-id:fake:payload
19510     89/<- %esi 4/r32/esp
19511 $test-add-literal-to-reg:initialize-outputs:
19512     # var outputs/edi: (payload stmt-var) = [v]
19513     68/push 0/imm32/is-deref:false
19514     68/push 0/imm32/next
19515     68/push 0/imm32/next
19516     51/push-ecx/v
19517     68/push 0x11/imm32/alloc-id:fake
19518     68/push 0x11/imm32/alloc-id:fake:payload
19519     89/<- %edi 4/r32/esp
19520 $test-add-literal-to-reg:initialize-stmt:
19521     # var stmt/esi: (addr statement)
19522     68/push 0/imm32/next
19523     68/push 0/imm32/next
19524     57/push-edi/outputs
19525     68/push 0x11/imm32/alloc-id:fake
19526     56/push-esi/inouts
19527     68/push 0x11/imm32/alloc-id:fake
19528     68/push 0/imm32/operation
19529     68/push 0/imm32/operation
19530     68/push 1/imm32/tag:stmt1
19531     89/<- %esi 4/r32/esp
19532 $test-add-literal-to-reg:initialize-stmt-operation:
19533     # stmt->operation = "add"
19534     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19535     (copy-array Heap "add" %eax)
19536     # convert
19537     c7 0/subop/copy *Curr-block-depth 0/imm32
19538     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19539     (flush _test-output-buffered-file)
19540 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19546     # check output
19547     (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
19548     # . epilogue
19549     89/<- %esp 5/r32/ebp
19550     5d/pop-to-ebp
19551     c3/return
19552 
19553 test-add-literal-to-mem:
19554     #   add-to var1, 0x34
19555     # =>
19556     #   81 0/subop/add %eax 0x34/imm32
19557     #
19558     # . prologue
19559     55/push-ebp
19560     89/<- %ebp 4/r32/esp
19561     # setup
19562     (clear-stream _test-output-stream)
19563     (clear-stream $_test-output-buffered-file->buffer)
19564 $test-add-literal-to-mem:initialize-type:
19565     # var type/ecx: (payload type-tree) = int
19566     68/push 0/imm32/right:null
19567     68/push 0/imm32/right:null
19568     68/push 0/imm32/left:unused
19569     68/push 1/imm32/value:int
19570     68/push 1/imm32/is-atom?:true
19571     68/push 0x11/imm32/alloc-id:fake:payload
19572     89/<- %ecx 4/r32/esp
19573 $test-add-literal-to-mem:initialize-var1:
19574     # var var1/ecx: (payload var)
19575     68/push 0/imm32/register
19576     68/push 0/imm32/register
19577     68/push 8/imm32/stack-offset
19578     68/push 1/imm32/block-depth
19579     51/push-ecx
19580     68/push 0x11/imm32/alloc-id:fake
19581     68/push 0/imm32/name
19582     68/push 0/imm32/name
19583     68/push 0x11/imm32/alloc-id:fake:payload
19584     89/<- %ecx 4/r32/esp
19585 $test-add-literal-to-mem:initialize-var1-name:
19586     # var1->name = "var1"
19587     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19588     (copy-array Heap "var1" %eax)
19589 $test-add-literal-to-mem:initialize-literal-type:
19590     # var type/edx: (payload type-tree) = literal
19591     68/push 0/imm32/right:null
19592     68/push 0/imm32/right:null
19593     68/push 0/imm32/left:unused
19594     68/push 0/imm32/value:literal
19595     68/push 1/imm32/is-atom?:true
19596     68/push 0x11/imm32/alloc-id:fake:payload
19597     89/<- %edx 4/r32/esp
19598 $test-add-literal-to-mem:initialize-literal:
19599     # var l/edx: (payload var)
19600     68/push 0/imm32/register
19601     68/push 0/imm32/register
19602     68/push 0/imm32/no-stack-offset
19603     68/push 1/imm32/block-depth
19604     52/push-edx
19605     68/push 0x11/imm32/alloc-id:fake
19606     68/push 0/imm32/name
19607     68/push 0/imm32/name
19608     68/push 0x11/imm32/alloc-id:fake:payload
19609     89/<- %edx 4/r32/esp
19610 $test-add-literal-to-mem:initialize-literal-value:
19611     # l->name = "0x34"
19612     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19613     (copy-array Heap "0x34" %eax)
19614 $test-add-literal-to-mem:initialize-inouts:
19615     # var inouts/esi: (payload stmt-var) = [l]
19616     68/push 0/imm32/is-deref:false
19617     68/push 0/imm32/next
19618     68/push 0/imm32/next
19619     52/push-edx/l
19620     68/push 0x11/imm32/alloc-id:fake
19621     68/push 0x11/imm32/alloc-id:fake:payload
19622     89/<- %esi 4/r32/esp
19623     # var inouts = (handle stmt-var) = [var1, var2]
19624     68/push 0/imm32/is-deref:false
19625     56/push-esi/next
19626     68/push 0x11/imm32/alloc-id:fake
19627     51/push-ecx/var1
19628     68/push 0x11/imm32/alloc-id:fake
19629     68/push 0x11/imm32/alloc-id:fake:payload
19630     89/<- %esi 4/r32/esp
19631 $test-add-literal-to-mem:initialize-stmt:
19632     # var stmt/esi: (addr statement)
19633     68/push 0/imm32/next
19634     68/push 0/imm32/next
19635     68/push 0/imm32/outputs
19636     68/push 0/imm32/outputs
19637     56/push-esi/inouts
19638     68/push 0x11/imm32/alloc-id:fake
19639     68/push 0/imm32/operation
19640     68/push 0/imm32/operation
19641     68/push 1/imm32/tag:stmt1
19642     89/<- %esi 4/r32/esp
19643 $test-add-literal-to-mem:initialize-stmt-operation:
19644     # stmt->operation = "add-to"
19645     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19646     (copy-array Heap "add-to" %eax)
19647     # convert
19648     c7 0/subop/copy *Curr-block-depth 0/imm32
19649     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19650     (flush _test-output-buffered-file)
19651 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19657     # check output
19658     (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
19659     # . epilogue
19660     89/<- %esp 5/r32/ebp
19661     5d/pop-to-ebp
19662     c3/return
19663 
19664 test-compare-reg-with-reg:
19665     #   compare var1/ecx, var2/eax
19666     # =>
19667     #   39/compare %ecx 0/r32/eax
19668     #
19669     # . prologue
19670     55/push-ebp
19671     89/<- %ebp 4/r32/esp
19672     # setup
19673     (clear-stream _test-output-stream)
19674     (clear-stream $_test-output-buffered-file->buffer)
19675 $test-compare-reg-with-reg:initialize-type:
19676     # var type/ecx: (payload type-tree) = int
19677     68/push 0/imm32/right:null
19678     68/push 0/imm32/right:null
19679     68/push 0/imm32/left:unused
19680     68/push 1/imm32/value:int
19681     68/push 1/imm32/is-atom?:true
19682     68/push 0x11/imm32/alloc-id:fake:payload
19683     89/<- %ecx 4/r32/esp
19684 $test-compare-reg-with-reg:initialize-var1:
19685     # var var1/ecx: (payload var)
19686     68/push 0/imm32/register
19687     68/push 0/imm32/register
19688     68/push 0/imm32/no-stack-offset
19689     68/push 1/imm32/block-depth
19690     51/push-ecx
19691     68/push 0x11/imm32/alloc-id:fake
19692     68/push 0/imm32/name
19693     68/push 0/imm32/name
19694     68/push 0x11/imm32/alloc-id:fake:payload
19695     89/<- %ecx 4/r32/esp
19696 $test-compare-reg-with-reg:initialize-var1-name:
19697     # var1->name = "var1"
19698     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19699     (copy-array Heap "var1" %eax)
19700 $test-compare-reg-with-reg:initialize-var1-register:
19701     # var1->register = "ecx"
19702     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19703     (copy-array Heap "ecx" %eax)
19704 $test-compare-reg-with-reg:initialize-var2:
19705     # var var2/edx: (payload var)
19706     68/push 0/imm32/register
19707     68/push 0/imm32/register
19708     68/push 0/imm32/no-stack-offset
19709     68/push 1/imm32/block-depth
19710     ff 6/subop/push *(ecx+0x10)
19711     68/push 0x11/imm32/alloc-id:fake
19712     68/push 0/imm32/name
19713     68/push 0/imm32/name
19714     68/push 0x11/imm32/alloc-id:fake:payload
19715     89/<- %edx 4/r32/esp
19716 $test-compare-reg-with-reg:initialize-var2-name:
19717     # var2->name = "var2"
19718     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19719     (copy-array Heap "var2" %eax)
19720 $test-compare-reg-with-reg:initialize-var2-register:
19721     # var2->register = "eax"
19722     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19723     (copy-array Heap "eax" %eax)
19724 $test-compare-reg-with-reg:initialize-inouts:
19725     # var inouts/esi: (payload stmt-var) = [var2]
19726     68/push 0/imm32/is-deref:false
19727     68/push 0/imm32/next
19728     68/push 0/imm32/next
19729     52/push-edx/var2
19730     68/push 0x11/imm32/alloc-id:fake
19731     68/push 0x11/imm32/alloc-id:fake:payload
19732     89/<- %esi 4/r32/esp
19733     # inouts = [var1, var2]
19734     68/push 0/imm32/is-deref:false
19735     56/push-esi/next
19736     68/push 0x11/imm32/alloc-id:fake
19737     51/push-ecx/var1
19738     68/push 0x11/imm32/alloc-id:fake
19739     68/push 0x11/imm32/alloc-id:fake:payload
19740     89/<- %esi 4/r32/esp
19741 $test-compare-reg-with-reg:initialize-stmt:
19742     # var stmt/esi: (addr statement)
19743     68/push 0/imm32/next
19744     68/push 0/imm32/next
19745     68/push 0/imm32/outputs
19746     68/push 0/imm32/outputs
19747     56/push-esi/inouts
19748     68/push 0x11/imm32/alloc-id:fake
19749     68/push 0/imm32/operation
19750     68/push 0/imm32/operation
19751     68/push 1/imm32/tag:stmt1
19752     89/<- %esi 4/r32/esp
19753 $test-compare-reg-with-reg:initialize-stmt-operation:
19754     # stmt->operation = "compare"
19755     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19756     (copy-array Heap "compare" %eax)
19757     # convert
19758     c7 0/subop/copy *Curr-block-depth 0/imm32
19759     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19760     (flush _test-output-buffered-file)
19761 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19767     # check output
19768     (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
19769     # . epilogue
19770     89/<- %esp 5/r32/ebp
19771     5d/pop-to-ebp
19772     c3/return
19773 
19774 test-compare-mem-with-reg:
19775     #   compare var1, var2/eax
19776     # =>
19777     #   39/compare *(ebp+___) 0/r32/eax
19778     #
19779     # . prologue
19780     55/push-ebp
19781     89/<- %ebp 4/r32/esp
19782     # setup
19783     (clear-stream _test-output-stream)
19784     (clear-stream $_test-output-buffered-file->buffer)
19785 $test-compare-mem-with-reg:initialize-type:
19786     # var type/ecx: (payload type-tree) = int
19787     68/push 0/imm32/right:null
19788     68/push 0/imm32/right:null
19789     68/push 0/imm32/left:unused
19790     68/push 1/imm32/value:int
19791     68/push 1/imm32/is-atom?:true
19792     68/push 0x11/imm32/alloc-id:fake:payload
19793     89/<- %ecx 4/r32/esp
19794 $test-compare-mem-with-reg:initialize-var1:
19795     # var var1/ecx: (payload var)
19796     68/push 0/imm32/register
19797     68/push 0/imm32/register
19798     68/push 8/imm32/stack-offset
19799     68/push 1/imm32/block-depth
19800     51/push-ecx
19801     68/push 0x11/imm32/alloc-id:fake
19802     68/push 0/imm32/name
19803     68/push 0/imm32/name
19804     68/push 0x11/imm32/alloc-id:fake:payload
19805     89/<- %ecx 4/r32/esp
19806 $test-compare-mem-with-reg:initialize-var1-name:
19807     # var1->name = "var1"
19808     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19809     (copy-array Heap "var1" %eax)
19810 $test-compare-mem-with-reg:initialize-var2:
19811     # var var2/edx: (payload var)
19812     68/push 0/imm32/register
19813     68/push 0/imm32/register
19814     68/push 0/imm32/no-stack-offset
19815     68/push 1/imm32/block-depth
19816     ff 6/subop/push *(ecx+0x10)
19817     68/push 0x11/imm32/alloc-id:fake
19818     68/push 0/imm32/name
19819     68/push 0/imm32/name
19820     68/push 0x11/imm32/alloc-id:fake:payload
19821     89/<- %edx 4/r32/esp
19822 $test-compare-mem-with-reg:initialize-var2-name:
19823     # var2->name = "var2"
19824     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19825     (copy-array Heap "var2" %eax)
19826 $test-compare-mem-with-reg:initialize-var2-register:
19827     # var2->register = "eax"
19828     8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
19829     (copy-array Heap "eax" %eax)
19830 $test-compare-mem-with-reg:initialize-inouts:
19831     # var inouts/esi: (payload stmt-var) = [var2]
19832     68/push 0/imm32/is-deref:false
19833     68/push 0/imm32/next
19834     68/push 0/imm32/next
19835     52/push-edx/var2
19836     68/push 0x11/imm32/alloc-id:fake
19837     68/push 0x11/imm32/alloc-id:fake:payload
19838     89/<- %esi 4/r32/esp
19839     # inouts = [var1, var2]
19840     68/push 0/imm32/is-deref:false
19841     56/push-esi/next
19842     68/push 0x11/imm32/alloc-id:fake
19843     51/push-ecx/var1
19844     68/push 0x11/imm32/alloc-id:fake
19845     68/push 0x11/imm32/alloc-id:fake:payload
19846     89/<- %esi 4/r32/esp
19847 $test-compare-mem-with-reg:initialize-stmt:
19848     # var stmt/esi: (addr statement)
19849     68/push 0/imm32/next
19850     68/push 0/imm32/next
19851     68/push 0/imm32/outputs
19852     68/push 0/imm32/outputs
19853     56/push-esi/inouts
19854     68/push 0x11/imm32/alloc-id:fake
19855     68/push 0/imm32/operation
19856     68/push 0/imm32/operation
19857     68/push 1/imm32/tag:stmt1
19858     89/<- %esi 4/r32/esp
19859 $test-compare-mem-with-reg:initialize-stmt-operation:
19860     # stmt->operation = "compare"
19861     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19862     (copy-array Heap "compare" %eax)
19863     # convert
19864     c7 0/subop/copy *Curr-block-depth 0/imm32
19865     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19866     (flush _test-output-buffered-file)
19867 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19873     # check output
19874     (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
19875     # . epilogue
19876     89/<- %esp 5/r32/ebp
19877     5d/pop-to-ebp
19878     c3/return
19879 
19880 test-compare-reg-with-mem:
19881     #   compare var1/eax, var2
19882     # =>
19883     #   3b/compare<- *(ebp+___) 0/r32/eax
19884     #
19885     # . prologue
19886     55/push-ebp
19887     89/<- %ebp 4/r32/esp
19888     # setup
19889     (clear-stream _test-output-stream)
19890     (clear-stream $_test-output-buffered-file->buffer)
19891 $test-compare-reg-with-mem:initialize-type:
19892     # var type/ecx: (payload type-tree) = int
19893     68/push 0/imm32/right:null
19894     68/push 0/imm32/right:null
19895     68/push 0/imm32/left:unused
19896     68/push 1/imm32/value:int
19897     68/push 1/imm32/is-atom?:true
19898     68/push 0x11/imm32/alloc-id:fake:payload
19899     89/<- %ecx 4/r32/esp
19900 $test-compare-reg-with-mem:initialize-var1:
19901     # var var1/ecx: (payload var)
19902     68/push 0/imm32/register
19903     68/push 0/imm32/register
19904     68/push 0/imm32/no-stack-offset
19905     68/push 1/imm32/block-depth
19906     51/push-ecx
19907     68/push 0x11/imm32/alloc-id:fake
19908     68/push 0/imm32/name
19909     68/push 0/imm32/name
19910     68/push 0x11/imm32/alloc-id:fake:payload
19911     89/<- %ecx 4/r32/esp
19912 $test-compare-reg-with-mem:initialize-var1-name:
19913     # var1->name = "var1"
19914     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
19915     (copy-array Heap "var1" %eax)
19916 $test-compare-reg-with-mem:initialize-var1-register:
19917     # var1->register = "eax"
19918     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
19919     (copy-array Heap "eax" %eax)
19920 $test-compare-reg-with-mem:initialize-var2:
19921     # var var2/edx: (payload var)
19922     68/push 0/imm32/register
19923     68/push 0/imm32/register
19924     68/push 8/imm32/stack-offset
19925     68/push 1/imm32/block-depth
19926     ff 6/subop/push *(ecx+0x10)
19927     68/push 0x11/imm32/alloc-id:fake
19928     68/push 0/imm32/name
19929     68/push 0/imm32/name
19930     68/push 0x11/imm32/alloc-id:fake:payload
19931     89/<- %edx 4/r32/esp
19932 $test-compare-reg-with-mem:initialize-var2-name:
19933     # var2->name = "var2"
19934     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
19935     (copy-array Heap "var2" %eax)
19936 $test-compare-reg-with-mem:initialize-inouts:
19937     # var inouts/esi: (payload stmt-var) = [var2]
19938     68/push 0/imm32/is-deref:false
19939     68/push 0/imm32/next
19940     68/push 0/imm32/next
19941     52/push-edx/var2
19942     68/push 0x11/imm32/alloc-id:fake
19943     68/push 0x11/imm32/alloc-id:fake:payload
19944     89/<- %esi 4/r32/esp
19945     # inouts = [var1, var2]
19946     68/push 0/imm32/is-deref:false
19947     56/push-esi/next
19948     68/push 0x11/imm32/alloc-id:fake
19949     51/push-ecx/var1
19950     68/push 0x11/imm32/alloc-id:fake
19951     68/push 0x11/imm32/alloc-id:fake:payload
19952     89/<- %esi 4/r32/esp
19953 $test-compare-reg-with-mem:initialize-stmt:
19954     # var stmt/esi: (addr statement)
19955     68/push 0/imm32/next
19956     68/push 0/imm32/next
19957     68/push 0/imm32/outputs
19958     68/push 0/imm32/outputs
19959     56/push-esi/inouts
19960     68/push 0x11/imm32/alloc-id:fake
19961     68/push 0/imm32/operation
19962     68/push 0/imm32/operation
19963     68/push 1/imm32/tag:stmt1
19964     89/<- %esi 4/r32/esp
19965 $test-compare-reg-with-mem:initialize-stmt-operation:
19966     # stmt->operation = "compare"
19967     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
19968     (copy-array Heap "compare" %eax)
19969     # convert
19970     c7 0/subop/copy *Curr-block-depth 0/imm32
19971     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
19972     (flush _test-output-buffered-file)
19973 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
19979     # check output
19980     (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
19981     # . epilogue
19982     89/<- %esp 5/r32/ebp
19983     5d/pop-to-ebp
19984     c3/return
19985 
19986 test-compare-mem-with-literal:
19987     #   compare var1, 0x34
19988     # =>
19989     #   81 7/subop/compare *(ebp+___) 0x34/imm32
19990     #
19991     # . prologue
19992     55/push-ebp
19993     89/<- %ebp 4/r32/esp
19994     # setup
19995     (clear-stream _test-output-stream)
19996     (clear-stream $_test-output-buffered-file->buffer)
19997 $test-compare-mem-with-literal:initialize-type:
19998     # var type/ecx: (payload type-tree) = int
19999     68/push 0/imm32/right:null
20000     68/push 0/imm32/right:null
20001     68/push 0/imm32/left:unused
20002     68/push 1/imm32/value:int
20003     68/push 1/imm32/is-atom?:true
20004     68/push 0x11/imm32/alloc-id:fake:payload
20005     89/<- %ecx 4/r32/esp
20006 $test-compare-mem-with-literal:initialize-var1:
20007     # var var1/ecx: (payload var)
20008     68/push 0/imm32/register
20009     68/push 0/imm32/register
20010     68/push 8/imm32/stack-offset
20011     68/push 1/imm32/block-depth
20012     51/push-ecx
20013     68/push 0x11/imm32/alloc-id:fake
20014     68/push 0/imm32/name
20015     68/push 0/imm32/name
20016     68/push 0x11/imm32/alloc-id:fake:payload
20017     89/<- %ecx 4/r32/esp
20018 $test-compare-mem-with-literal:initialize-var1-name:
20019     # var1->name = "var1"
20020     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20021     (copy-array Heap "var1" %eax)
20022 $test-compare-mem-with-literal:initialize-literal-type:
20023     # var type/edx: (payload type-tree) = literal
20024     68/push 0/imm32/right:null
20025     68/push 0/imm32/right:null
20026     68/push 0/imm32/left:unused
20027     68/push 0/imm32/value:literal
20028     68/push 1/imm32/is-atom?:true
20029     68/push 0x11/imm32/alloc-id:fake:payload
20030     89/<- %edx 4/r32/esp
20031 $test-compare-mem-with-literal:initialize-literal:
20032     # var l/edx: (payload var)
20033     68/push 0/imm32/register
20034     68/push 0/imm32/register
20035     68/push 0/imm32/no-stack-offset
20036     68/push 1/imm32/block-depth
20037     52/push-edx
20038     68/push 0x11/imm32/alloc-id:fake
20039     68/push 0/imm32/name
20040     68/push 0/imm32/name
20041     68/push 0x11/imm32/alloc-id:fake:payload
20042     89/<- %edx 4/r32/esp
20043 $test-compare-mem-with-literal:initialize-literal-value:
20044     # l->name = "0x34"
20045     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20046     (copy-array Heap "0x34" %eax)
20047 $test-compare-mem-with-literal:initialize-inouts:
20048     # var inouts/esi: (payload stmt-var) = [l]
20049     68/push 0/imm32/is-deref:false
20050     68/push 0/imm32/next
20051     68/push 0/imm32/next
20052     52/push-edx/l
20053     68/push 0x11/imm32/alloc-id:fake
20054     68/push 0x11/imm32/alloc-id:fake:payload
20055     89/<- %esi 4/r32/esp
20056     # var inouts = (handle stmt-var) = [var1, var2]
20057     68/push 0/imm32/is-deref:false
20058     56/push-esi/next
20059     68/push 0x11/imm32/alloc-id:fake
20060     51/push-ecx/var1
20061     68/push 0x11/imm32/alloc-id:fake
20062     68/push 0x11/imm32/alloc-id:fake:payload
20063     89/<- %esi 4/r32/esp
20064 $test-compare-mem-with-literal:initialize-stmt:
20065     # var stmt/esi: (addr statement)
20066     68/push 0/imm32/next
20067     68/push 0/imm32/next
20068     68/push 0/imm32/outputs
20069     68/push 0/imm32/outputs
20070     56/push-esi/inouts
20071     68/push 0x11/imm32/alloc-id:fake
20072     68/push 0/imm32/operation
20073     68/push 0/imm32/operation
20074     68/push 1/imm32/tag:stmt1
20075     89/<- %esi 4/r32/esp
20076 $test-compare-mem-with-literal:initialize-stmt-operation:
20077     # stmt->operation = "compare"
20078     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20079     (copy-array Heap "compare" %eax)
20080     # convert
20081     c7 0/subop/copy *Curr-block-depth 0/imm32
20082     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20083     (flush _test-output-buffered-file)
20084 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20090     # check output
20091     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
20092     # . epilogue
20093     89/<- %esp 5/r32/ebp
20094     5d/pop-to-ebp
20095     c3/return
20096 
20097 test-compare-eax-with-literal:
20098     #   compare var1/eax 0x34
20099     # =>
20100     #   3d/compare-eax-with 0x34/imm32
20101     #
20102     # . prologue
20103     55/push-ebp
20104     89/<- %ebp 4/r32/esp
20105     # setup
20106     (clear-stream _test-output-stream)
20107     (clear-stream $_test-output-buffered-file->buffer)
20108 $test-compare-eax-with-literal:initialize-type:
20109     # var type/ecx: (payload type-tree) = int
20110     68/push 0/imm32/right:null
20111     68/push 0/imm32/right:null
20112     68/push 0/imm32/left:unused
20113     68/push 1/imm32/value:int
20114     68/push 1/imm32/is-atom?:true
20115     68/push 0x11/imm32/alloc-id:fake:payload
20116     89/<- %ecx 4/r32/esp
20117 $test-compare-eax-with-literal:initialize-var1:
20118     # var var1/ecx: (payload var)
20119     68/push 0/imm32/register
20120     68/push 0/imm32/register
20121     68/push 0/imm32/no-stack-offset
20122     68/push 1/imm32/block-depth
20123     51/push-ecx
20124     68/push 0x11/imm32/alloc-id:fake
20125     68/push 0/imm32/name
20126     68/push 0/imm32/name
20127     68/push 0x11/imm32/alloc-id:fake:payload
20128     89/<- %ecx 4/r32/esp
20129 $test-compare-eax-with-literal:initialize-var1-name:
20130     # var1->name = "var1"
20131     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20132     (copy-array Heap "var1" %eax)
20133 $test-compare-eax-with-literal:initialize-var1-register:
20134     # v->register = "eax"
20135     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20136     (copy-array Heap "eax" %eax)
20137 $test-compare-eax-with-literal:initialize-literal-type:
20138     # var type/edx: (payload type-tree) = literal
20139     68/push 0/imm32/right:null
20140     68/push 0/imm32/right:null
20141     68/push 0/imm32/left:unused
20142     68/push 0/imm32/value:literal
20143     68/push 1/imm32/is-atom?:true
20144     68/push 0x11/imm32/alloc-id:fake:payload
20145     89/<- %edx 4/r32/esp
20146 $test-compare-eax-with-literal:initialize-literal:
20147     # var l/edx: (payload var)
20148     68/push 0/imm32/register
20149     68/push 0/imm32/register
20150     68/push 0/imm32/no-stack-offset
20151     68/push 1/imm32/block-depth
20152     52/push-edx
20153     68/push 0x11/imm32/alloc-id:fake
20154     68/push 0/imm32/name
20155     68/push 0/imm32/name
20156     68/push 0x11/imm32/alloc-id:fake:payload
20157     89/<- %edx 4/r32/esp
20158 $test-compare-eax-with-literal:initialize-literal-value:
20159     # l->name = "0x34"
20160     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20161     (copy-array Heap "0x34" %eax)
20162 $test-compare-eax-with-literal:initialize-inouts:
20163     # var inouts/esi: (payload stmt-var) = [l]
20164     68/push 0/imm32/is-deref:false
20165     68/push 0/imm32/next
20166     68/push 0/imm32/next
20167     52/push-edx/l
20168     68/push 0x11/imm32/alloc-id:fake
20169     68/push 0x11/imm32/alloc-id:fake:payload
20170     89/<- %esi 4/r32/esp
20171     # var inouts = (handle stmt-var) = [var1, var2]
20172     68/push 0/imm32/is-deref:false
20173     56/push-esi/next
20174     68/push 0x11/imm32/alloc-id:fake
20175     51/push-ecx/var1
20176     68/push 0x11/imm32/alloc-id:fake
20177     68/push 0x11/imm32/alloc-id:fake:payload
20178     89/<- %esi 4/r32/esp
20179 $test-compare-eax-with-literal:initialize-stmt:
20180     # var stmt/esi: (addr statement)
20181     68/push 0/imm32/next
20182     68/push 0/imm32/next
20183     68/push 0/imm32/outputs
20184     68/push 0/imm32/outputs
20185     56/push-esi/inouts
20186     68/push 0x11/imm32/alloc-id:fake
20187     68/push 0/imm32/operation
20188     68/push 0/imm32/operation
20189     68/push 1/imm32/tag:stmt1
20190     89/<- %esi 4/r32/esp
20191 $test-compare-eax-with-literal:initialize-stmt-operation:
20192     # stmt->operation = "compare"
20193     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20194     (copy-array Heap "compare" %eax)
20195     # convert
20196     c7 0/subop/copy *Curr-block-depth 0/imm32
20197     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20198     (flush _test-output-buffered-file)
20199 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20205     # check output
20206     (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
20207     # . epilogue
20208     89/<- %esp 5/r32/ebp
20209     5d/pop-to-ebp
20210     c3/return
20211 
20212 test-compare-reg-with-literal:
20213     #   compare var1/ecx 0x34
20214     # =>
20215     #   81 7/subop/compare %ecx 0x34/imm32
20216     #
20217     # . prologue
20218     55/push-ebp
20219     89/<- %ebp 4/r32/esp
20220     # setup
20221     (clear-stream _test-output-stream)
20222     (clear-stream $_test-output-buffered-file->buffer)
20223 $test-compare-reg-with-literal:initialize-type:
20224     # var type/ecx: (payload type-tree) = int
20225     68/push 0/imm32/right:null
20226     68/push 0/imm32/right:null
20227     68/push 0/imm32/left:unused
20228     68/push 1/imm32/value:int
20229     68/push 1/imm32/is-atom?:true
20230     68/push 0x11/imm32/alloc-id:fake:payload
20231     89/<- %ecx 4/r32/esp
20232 $test-compare-reg-with-literal:initialize-var1:
20233     # var var1/ecx: (payload var)
20234     68/push 0/imm32/register
20235     68/push 0/imm32/register
20236     68/push 0/imm32/no-stack-offset
20237     68/push 1/imm32/block-depth
20238     51/push-ecx
20239     68/push 0x11/imm32/alloc-id:fake
20240     68/push 0/imm32/name
20241     68/push 0/imm32/name
20242     68/push 0x11/imm32/alloc-id:fake:payload
20243     89/<- %ecx 4/r32/esp
20244 $test-compare-reg-with-literal:initialize-var1-name:
20245     # var1->name = "var1"
20246     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20247     (copy-array Heap "var1" %eax)
20248 $test-compare-reg-with-literal:initialize-var1-register:
20249     # v->register = "ecx"
20250     8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
20251     (copy-array Heap "ecx" %eax)
20252 $test-compare-reg-with-literal:initialize-literal-type:
20253     # var type/edx: (payload type-tree) = literal
20254     68/push 0/imm32/right:null
20255     68/push 0/imm32/right:null
20256     68/push 0/imm32/left:unused
20257     68/push 0/imm32/value:literal
20258     68/push 1/imm32/is-atom?:true
20259     68/push 0x11/imm32/alloc-id:fake:payload
20260     89/<- %edx 4/r32/esp
20261 $test-compare-reg-with-literal:initialize-literal:
20262     # var l/edx: (payload var)
20263     68/push 0/imm32/register
20264     68/push 0/imm32/register
20265     68/push 0/imm32/no-stack-offset
20266     68/push 1/imm32/block-depth
20267     52/push-edx
20268     68/push 0x11/imm32/alloc-id:fake
20269     68/push 0/imm32/name
20270     68/push 0/imm32/name
20271     68/push 0x11/imm32/alloc-id:fake:payload
20272     89/<- %edx 4/r32/esp
20273 $test-compare-reg-with-literal:initialize-literal-value:
20274     # l->name = "0x34"
20275     8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
20276     (copy-array Heap "0x34" %eax)
20277 $test-compare-reg-with-literal:initialize-inouts:
20278     # var inouts/esi: (payload stmt-var) = [l]
20279     68/push 0/imm32/is-deref:false
20280     68/push 0/imm32/next
20281     68/push 0/imm32/next
20282     52/push-edx/l
20283     68/push 0x11/imm32/alloc-id:fake
20284     68/push 0x11/imm32/alloc-id:fake:payload
20285     89/<- %esi 4/r32/esp
20286     # var inouts = (handle stmt-var) = [var1, var2]
20287     68/push 0/imm32/is-deref:false
20288     56/push-esi/next
20289     68/push 0x11/imm32/alloc-id:fake
20290     51/push-ecx/var1
20291     68/push 0x11/imm32/alloc-id:fake
20292     68/push 0x11/imm32/alloc-id:fake:payload
20293     89/<- %esi 4/r32/esp
20294 $test-compare-reg-with-literal:initialize-stmt:
20295     # var stmt/esi: (addr statement)
20296     68/push 0/imm32/next
20297     68/push 0/imm32/next
20298     68/push 0/imm32/outputs
20299     68/push 0/imm32/outputs
20300     56/push-esi/inouts
20301     68/push 0x11/imm32/alloc-id:fake
20302     68/push 0/imm32/operation
20303     68/push 0/imm32/operation
20304     68/push 1/imm32/tag:stmt1
20305     89/<- %esi 4/r32/esp
20306 $test-compare-reg-with-literal:initialize-stmt-operation:
20307     # stmt->operation = "compare"
20308     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20309     (copy-array Heap "compare" %eax)
20310     # convert
20311     c7 0/subop/copy *Curr-block-depth 0/imm32
20312     (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
20313     (flush _test-output-buffered-file)
20314 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20320     # check output
20321     (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
20322     # . epilogue
20323     89/<- %esp 5/r32/ebp
20324     5d/pop-to-ebp
20325     c3/return
20326 
20327 test-emit-subx-stmt-function-call:
20328     # Call a function on a variable on the stack.
20329     #   f foo
20330     # =>
20331     #   (f *(ebp-8))
20332     # (Changing the function name supports overloading in general, but here it
20333     # just serves to help disambiguate things.)
20334     #
20335     # There's a variable on the var stack as follows:
20336     #   name: 'foo'
20337     #   type: int
20338     #   stack-offset: -8
20339     #
20340     # There's nothing in primitives.
20341     #
20342     # We don't perform any checking here on the type of 'f'.
20343     #
20344     # . prologue
20345     55/push-ebp
20346     89/<- %ebp 4/r32/esp
20347     # setup
20348     (clear-stream _test-output-stream)
20349     (clear-stream $_test-output-buffered-file->buffer)
20350 $test-emit-subx-function-call:initialize-type:
20351     # var type/ecx: (payload type-tree) = int
20352     68/push 0/imm32/right:null
20353     68/push 0/imm32/right:null
20354     68/push 0/imm32/left:unused
20355     68/push 1/imm32/value:int
20356     68/push 1/imm32/is-atom?:true
20357     68/push 0x11/imm32/alloc-id:fake:payload
20358     89/<- %ecx 4/r32/esp
20359 $test-emit-subx-function-call:initialize-var:
20360     # var var-foo/ecx: (payload var) = var(type)
20361     68/push 0/imm32/no-register
20362     68/push 0/imm32/no-register
20363     68/push -8/imm32/stack-offset
20364     68/push 1/imm32/block-depth
20365     51/push-ecx/type
20366     68/push 0x11/imm32/alloc-id:fake
20367     68/push 0/imm32/name
20368     68/push 0/imm32/name
20369     68/push 0x11/imm32/alloc-id:fake:payload
20370     89/<- %ecx 4/r32/esp
20371 $test-emit-subx-function-call:initialize-var-name:
20372     # var-foo->name = "foo"
20373     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20374     (copy-array Heap "foo" %eax)
20375 $test-emit-subx-function-call:initialize-stmt-var:
20376     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20377     68/push 0/imm32/is-deref:false
20378     68/push 0/imm32/next
20379     68/push 0/imm32/next
20380     51/push-ecx/var-foo
20381     68/push 0x11/imm32/alloc-id:fake
20382     68/push 0x11/imm32/alloc-id:fake:payload
20383     89/<- %ebx 4/r32/esp
20384 $test-emit-subx-function-call:initialize-stmt:
20385     # var stmt/esi: (addr statement)
20386     68/push 0/imm32/no-outputs
20387     68/push 0/imm32/no-outputs
20388     53/push-ebx/inouts
20389     68/push 0x11/imm32/alloc-id:fake
20390     68/push 0/imm32/operation
20391     68/push 0/imm32/operation
20392     68/push 1/imm32/tag
20393     89/<- %esi 4/r32/esp
20394 $test-emit-subx-function-call:initialize-stmt-operation:
20395     # stmt->operation = "f"
20396     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20397     (copy-array Heap "f" %eax)
20398     # convert
20399     c7 0/subop/copy *Curr-block-depth 0/imm32
20400     (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
20401     (flush _test-output-buffered-file)
20402 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20408     # check output
20409     (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
20410     # . epilogue
20411     89/<- %esp 5/r32/ebp
20412     5d/pop-to-ebp
20413     c3/return
20414 
20415 test-emit-subx-stmt-function-call-with-literal-arg:
20416     # Call a function on a literal.
20417     #   f 0x34
20418     # =>
20419     #   (f2 0x34)
20420     #
20421     # . prologue
20422     55/push-ebp
20423     89/<- %ebp 4/r32/esp
20424     # setup
20425     (clear-stream _test-output-stream)
20426     (clear-stream $_test-output-buffered-file->buffer)
20427 $test-emit-subx-function-call-with-literal-arg:initialize-type:
20428     # var type/ecx: (payload type-tree) = int
20429     68/push 0/imm32/right:null
20430     68/push 0/imm32/right:null
20431     68/push 0/imm32/left:unused
20432     68/push 0/imm32/value:literal
20433     68/push 1/imm32/is-atom?:true
20434     68/push 0x11/imm32/alloc-id:fake:payload
20435     89/<- %ecx 4/r32/esp
20436 $test-emit-subx-function-call-with-literal-arg:initialize-var:
20437     # var var-foo/ecx: (payload var) = var(lit)
20438     68/push 0/imm32/no-register
20439     68/push 0/imm32/no-register
20440     68/push 0/imm32/no-stack-offset
20441     68/push 1/imm32/block-depth
20442     51/push-ecx/type
20443     68/push 0x11/imm32/alloc-id:fake
20444     68/push 0/imm32/name
20445     68/push 0/imm32/name
20446     68/push 0x11/imm32/alloc-id:fake:payload
20447     89/<- %ecx 4/r32/esp
20448 $test-emit-subx-function-call-with-literal-arg:initialize-var-name:
20449     # var-foo->name = "0x34"
20450     8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
20451     (copy-array Heap "0x34" %eax)
20452 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
20453     # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
20454     68/push 0/imm32/is-deref:false
20455     68/push 0/imm32/next
20456     68/push 0/imm32/next
20457     51/push-ecx/var-foo
20458     68/push 0x11/imm32/alloc-id:fake
20459     68/push 0x11/imm32/alloc-id:fake:payload
20460     89/<- %ebx 4/r32/esp
20461 $test-emit-subx-function-call-with-literal-arg:initialize-stmt:
20462     # var stmt/esi: (addr statement)
20463     68/push 0/imm32/no-outputs
20464     68/push 0/imm32/no-outputs
20465     53/push-ebx/inouts
20466     68/push 0x11/imm32/alloc-id:fake
20467     68/push 0/imm32/operation
20468     68/push 0/imm32/operation
20469     68/push 1/imm32/tag
20470     89/<- %esi 4/r32/esp
20471 $test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
20472     # stmt->operation = "f"
20473     8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
20474     (copy-array Heap "f" %eax)
20475     # convert
20476     c7 0/subop/copy *Curr-block-depth 0/imm32
20477     (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
20478     (flush _test-output-buffered-file)
20479 +--  6 lines: #?     # dump _test-output-stream -----------------------------------------------------------------------------------------------------------------------------------------
20485     # check output
20486     (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
20487     # . epilogue
20488     89/<- %esp 5/r32/ebp
20489     5d/pop-to-ebp
20490     c3/return
20491 
20492 emit-indent:  # out: (addr buffered-file), n: int
20493     # . prologue
20494     55/push-ebp
20495     89/<- %ebp 4/r32/esp
20496     # . save registers
20497     50/push-eax
20498     # var i/eax: int = n
20499     8b/-> *(ebp+0xc) 0/r32/eax
20500     {
20501       # if (i <= 0) break
20502       3d/compare-eax-with 0/imm32
20503       7e/jump-if-<= break/disp8
20504       (write-buffered *(ebp+8) "  ")
20505       48/decrement-eax
20506       eb/jump loop/disp8
20507     }
20508 $emit-indent:end:
20509     # . restore registers
20510     58/pop-to-eax
20511     # . epilogue
20512     89/<- %esp 5/r32/ebp
20513     5d/pop-to-ebp
20514     c3/return
20515 
20516 emit-subx-prologue:  # out: (addr buffered-file)
20517     # . prologue
20518     55/push-ebp
20519     89/<- %ebp 4/r32/esp
20520     #
20521     (write-buffered *(ebp+8) "  # . prologue\n")
20522     (write-buffered *(ebp+8) "  55/push-ebp\n")
20523     (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
20524 $emit-subx-prologue:end:
20525     # . epilogue
20526     89/<- %esp 5/r32/ebp
20527     5d/pop-to-ebp
20528     c3/return
20529 
20530 emit-subx-epilogue:  # out: (addr buffered-file)
20531     # . prologue
20532     55/push-ebp
20533     89/<- %ebp 4/r32/esp
20534     #
20535     (write-buffered *(ebp+8) "  # . epilogue\n")
20536     (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
20537     (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
20538     (write-buffered *(ebp+8) "  c3/return\n")
20539 $emit-subx-epilogue:end:
20540     # . epilogue
20541     89/<- %esp 5/r32/ebp
20542     5d/pop-to-ebp
20543     c3/return